Added speex to 3rdparty directory

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@1116 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/3rdparty/speex/libspeex/.cvsignore b/3rdparty/speex/libspeex/.cvsignore
new file mode 100644
index 0000000..09a90ac
--- /dev/null
+++ b/3rdparty/speex/libspeex/.cvsignore
@@ -0,0 +1,11 @@
+.deps
+.libs
+*.la
+*.lo
+*.o
+Makefile
+Makefile.in
+testdenoise
+testenc
+testenc_uwb
+testenc_wb
diff --git a/3rdparty/speex/libspeex/Makefile.am b/3rdparty/speex/libspeex/Makefile.am
new file mode 100644
index 0000000..ff6d4bc
--- /dev/null
+++ b/3rdparty/speex/libspeex/Makefile.am
@@ -0,0 +1,42 @@
+# Disable automatic dependency tracking if using other tools than gcc and gmake
+#AUTOMAKE_OPTIONS = no-dependencies
+
+
+EXTRA_DIST=echo_diagnostic.m
+
+INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_builddir) @OGG_CFLAGS@
+
+lib_LTLIBRARIES = libspeex.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 filterbank.c resample.c
+
+noinst_HEADERS = lsp.h 	nb_celp.h 	lpc.h 	lpc_bfin.h 	ltp.h 	quant_lsp.h \
+				cb_search.h 	filters.h 	stack_alloc.h 	vq.h 	vq_sse.h 	vq_arm4.h 	vq_bfin.h \
+				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 filterbank.h
+
+
+libspeex_la_LDFLAGS = -no-undefined -version-info @SPEEX_LT_CURRENT@:@SPEEX_LT_REVISION@:@SPEEX_LT_AGE@
+
+noinst_PROGRAMS = testenc testenc_wb testenc_uwb testdenoise testecho
+testenc_SOURCES = testenc.c
+testenc_LDADD = libspeex.la
+testenc_wb_SOURCES = testenc_wb.c
+testenc_wb_LDADD = libspeex.la
+testenc_uwb_SOURCES = testenc_uwb.c
+testenc_uwb_LDADD = libspeex.la
+testdenoise_SOURCES = testdenoise.c
+testdenoise_LDADD = libspeex.la
+testecho_SOURCES = testecho.c
+testecho_LDADD = libspeex.la
diff --git a/3rdparty/speex/libspeex/_kiss_fft_guts.h b/3rdparty/speex/libspeex/_kiss_fft_guts.h
new file mode 100644
index 0000000..526a73b
--- /dev/null
+++ b/3rdparty/speex/libspeex/_kiss_fft_guts.h
@@ -0,0 +1,160 @@
+/*
+Copyright (c) 2003-2004, Mark Borgerding
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+    * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
+*/
+
+#define MIN(a,b) ((a)<(b) ? (a):(b))
+#define MAX(a,b) ((a)>(b) ? (a):(b))
+
+/* kiss_fft.h
+   defines kiss_fft_scalar as either short or a float type
+   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 
+ as far as kissfft is concerned
+ 4*4*4*2
+ */
+
+struct kiss_fft_state{
+    int nfft;
+    int inverse;
+    int factors[2*MAXFACTORS];
+    kiss_fft_cpx twiddles[1];
+};
+
+/*
+  Explanation of macros dealing with complex math:
+
+   C_MUL(m,a,b)         : m = a*b
+   C_FIXDIV( c , div )  : if a fixed point impl., c /= div. noop otherwise
+   C_SUB( res, a,b)     : res = a - b
+   C_SUBFROM( res , a)  : res -= a
+   C_ADDTO( res , a)    : res += a
+ * */
+#ifdef FIXED_POINT
+#include "misc.h"
+# define FRACBITS 15
+# define SAMPPROD spx_int32_t 
+#define SAMP_MAX 32767
+
+#define SAMP_MIN -SAMP_MAX
+
+#if defined(CHECK_OVERFLOW)
+#  define CHECK_OVERFLOW_OP(a,op,b)  \
+	if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \
+		fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) );  }
+#endif
+
+
+#   define smul(a,b) ( (SAMPPROD)(a)*(b) )
+#   define sround( x )  (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRACBITS )
+
+#   define S_MUL(a,b) sround( smul(a,b) )
+
+#   define C_MUL(m,a,b) \
+      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 ) )
+
+#   define C_FIXDIV(c,div) \
+	do {    DIVSCALAR( (c).r , div);  \
+		DIVSCALAR( (c).i  , div); }while (0)
+
+#   define C_MULBYSCALAR( c, s ) \
+    do{ (c).r =  sround( smul( (c).r , s ) ) ;\
+        (c).i =  sround( smul( (c).i , s ) ) ; }while(0)
+
+#else  /* not FIXED_POINT*/
+
+#   define S_MUL(a,b) ( (a)*(b) )
+#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);\
+        (c).i *= (s); }while(0)
+#endif
+
+#ifndef CHECK_OVERFLOW_OP
+#  define CHECK_OVERFLOW_OP(a,op,b) /* noop */
+#endif
+
+#define  C_ADD( res, a,b)\
+    do { \
+	    CHECK_OVERFLOW_OP((a).r,+,(b).r)\
+	    CHECK_OVERFLOW_OP((a).i,+,(b).i)\
+	    (res).r=(a).r+(b).r;  (res).i=(a).i+(b).i; \
+    }while(0)
+#define  C_SUB( res, a,b)\
+    do { \
+	    CHECK_OVERFLOW_OP((a).r,-,(b).r)\
+	    CHECK_OVERFLOW_OP((a).i,-,(b).i)\
+	    (res).r=(a).r-(b).r;  (res).i=(a).i-(b).i; \
+    }while(0)
+#define C_ADDTO( res , a)\
+    do { \
+	    CHECK_OVERFLOW_OP((res).r,+,(a).r)\
+	    CHECK_OVERFLOW_OP((res).i,+,(a).i)\
+	    (res).r += (a).r;  (res).i += (a).i;\
+    }while(0)
+
+#define C_SUBFROM( res , a)\
+    do {\
+	    CHECK_OVERFLOW_OP((res).r,-,(a).r)\
+	    CHECK_OVERFLOW_OP((res).i,-,(a).i)\
+	    (res).r -= (a).r;  (res).i -= (a).i; \
+    }while(0)
+
+
+#ifdef FIXED_POINT
+#  define KISS_FFT_COS(phase)  floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase))))
+#  define KISS_FFT_SIN(phase)  floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase))))
+#  define HALF_OF(x) ((x)>>1)
+#elif defined(USE_SIMD)
+#  define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) )
+#  define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) )
+#  define HALF_OF(x) ((x)*_mm_set1_ps(.5))
+#else
+#  define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase)
+#  define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase)
+#  define HALF_OF(x) ((x)*.5)
+#endif
+
+#define  kf_cexp(x,phase) \
+	do{ \
+		(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 */
+#define pcpx(c)\
+    fprintf(stderr,"%g + %gi\n",(double)((c)->r),(double)((c)->i) )
diff --git a/3rdparty/speex/libspeex/arch.h b/3rdparty/speex/libspeex/arch.h
new file mode 100644
index 0000000..e2d731a
--- /dev/null
+++ b/3rdparty/speex/libspeex/arch.h
@@ -0,0 +1,197 @@
+/* Copyright (C) 2003 Jean-Marc Valin */
+/**
+   @file arch.h
+   @brief Various architecture definitions Speex
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef ARCH_H
+#define ARCH_H
+
+#ifndef OUTSIDE_SPEEX
+#include "speex/speex_types.h"
+#endif
+
+#define ABS(x) ((x) < 0 ? (-(x)) : (x))      /**< Absolute integer value. */
+#define ABS16(x) ((x) < 0 ? (-(x)) : (x))    /**< Absolute 16-bit value.  */
+#define MIN16(a,b) ((a) < (b) ? (a) : (b))   /**< Maximum 16-bit value.   */
+#define MAX16(a,b) ((a) > (b) ? (a) : (b))   /**< Maximum 16-bit value.   */
+#define ABS32(x) ((x) < 0 ? (-(x)) : (x))    /**< Absolute 32-bit value.  */
+#define MIN32(a,b) ((a) < (b) ? (a) : (b))   /**< Maximum 32-bit value.   */
+#define MAX32(a,b) ((a) > (b) ? (a) : (b))   /**< Maximum 32-bit value.   */
+
+#ifdef FIXED_POINT
+
+typedef spx_int16_t spx_word16_t;
+typedef spx_int32_t   spx_word32_t;
+typedef spx_word32_t spx_mem_t;
+typedef spx_word16_t spx_coef_t;
+typedef spx_word16_t spx_lsp_t;
+typedef spx_word32_t spx_sig_t;
+
+#define Q15ONE 32767
+
+#define LPC_SCALING  8192
+#define SIG_SCALING  16384
+#define LSP_SCALING  8192.
+#define GAMMA_SCALING 32768.
+#define GAIN_SCALING 64
+#define GAIN_SCALING_1 0.015625
+
+#define LPC_SHIFT    13
+#define LSP_SHIFT    13
+#define SIG_SHIFT    14
+
+#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
+#include "fixed_debug.h"
+#else
+
+#include "fixed_generic.h"
+
+#ifdef ARM5E_ASM
+#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
+
+#endif
+
+
+#else
+
+typedef float spx_mem_t;
+typedef float spx_coef_t;
+typedef float spx_lsp_t;
+typedef float spx_sig_t;
+typedef float spx_word16_t;
+typedef float spx_word32_t;
+
+#define Q15ONE 1.0f
+#define LPC_SCALING  1.f
+#define SIG_SCALING  1.f
+#define LSP_SCALING  1.f
+#define GAMMA_SCALING 1.f
+#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)
+
+#define NEG16(x) (-(x))
+#define NEG32(x) (-(x))
+#define EXTRACT16(x) (x)
+#define EXTEND32(x) (x)
+#define SHR16(a,shift) (a)
+#define SHL16(a,shift) (a)
+#define SHR32(a,shift) (a)
+#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)
+
+#define PSHR(a,shift)       (a)
+#define SHR(a,shift)       (a)
+#define SHL(a,shift)       (a)
+#define SATURATE(x,a) (x)
+
+#define ADD16(a,b) ((a)+(b))
+#define SUB16(a,b) ((a)-(b))
+#define ADD32(a,b) ((a)+(b))
+#define SUB32(a,b) ((a)-(b))
+#define MULT16_16_16(a,b)     ((a)*(b))
+#define MULT16_16(a,b)     ((spx_word32_t)(a)*(spx_word32_t)(b))
+#define MAC16_16(c,a,b)     ((c)+(spx_word32_t)(a)*(spx_word32_t)(b))
+
+#define MULT16_32_Q11(a,b)     ((a)*(b))
+#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))
+
+#define MAC16_16_Q11(c,a,b)     ((c)+(a)*(b))
+#define MAC16_16_Q13(c,a,b)     ((c)+(a)*(b))
+#define MAC16_16_P13(c,a,b)     ((c)+(a)*(b))
+#define MULT16_16_Q11_32(a,b)     ((a)*(b))
+#define MULT16_16_Q13(a,b)     ((a)*(b))
+#define MULT16_16_Q14(a,b)     ((a)*(b))
+#define MULT16_16_Q15(a,b)     ((a)*(b))
+#define MULT16_16_P15(a,b)     ((a)*(b))
+#define MULT16_16_P13(a,b)     ((a)*(b))
+#define MULT16_16_P14(a,b)     ((a)*(b))
+
+#define DIV32_16(a,b)     (((spx_word32_t)(a))/(spx_word16_t)(b))
+#define PDIV32_16(a,b)     (((spx_word32_t)(a))/(spx_word16_t)(b))
+#define DIV32(a,b)     (((spx_word32_t)(a))/(spx_word32_t)(b))
+#define PDIV32(a,b)     (((spx_word32_t)(a))/(spx_word32_t)(b))
+
+
+#endif
+
+
+#if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)
+
+/* 2 on TI C5x DSP */
+#define BYTES_PER_CHAR 2 
+#define BITS_PER_CHAR 16
+#define LOG2_BITS_PER_CHAR 4
+
+#else 
+
+#define BYTES_PER_CHAR 1
+#define BITS_PER_CHAR 8
+#define LOG2_BITS_PER_CHAR 3
+
+#endif
+
+#endif
diff --git a/3rdparty/speex/libspeex/bits.c b/3rdparty/speex/libspeex/bits.c
new file mode 100644
index 0000000..5c4cb0e
--- /dev/null
+++ b/3rdparty/speex/libspeex/bits.c
@@ -0,0 +1,363 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: speex_bits.c
+
+   Handles bit packing/unpacking
+
+   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 <speex/speex_bits.h>
+#include "misc.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)
+{
+   bits->chars = (char*)speex_alloc(MAX_CHARS_PER_FRAME);
+   if (!bits->chars)
+      return;
+
+   bits->buf_size = MAX_CHARS_PER_FRAME;
+
+   bits->owner=1;
+
+   speex_bits_reset(bits);
+}
+
+void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size)
+{
+   bits->chars = (char*)buff;
+   bits->buf_size = buf_size;
+
+   bits->owner=0;
+
+   speex_bits_reset(bits);
+}
+
+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)
+{
+   /* We only need to clear the first byte now */
+   bits->chars[0]=0;
+   bits->nbBits=0;
+   bits->charPtr=0;
+   bits->bitPtr=0;
+   bits->overflow=0;
+}
+
+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)
+{
+   int i;
+   int nchars = len / BYTES_PER_CHAR;
+   if (nchars > bits->buf_size)
+   {
+      speex_notify("Packet is larger than allocated buffer");
+      if (bits->owner)
+      {
+         char *tmp = (char*)speex_realloc(bits->chars, nchars);
+         if (tmp)
+         {
+            bits->buf_size=nchars;
+            bits->chars=tmp;
+         } else {
+            nchars=bits->buf_size;
+            speex_warning("Could not resize input buffer: truncating input");
+         }
+      } else {
+         speex_warning("Do not own input buffer: truncating oversize input");
+         nchars=bits->buf_size;
+      }
+   }
+#if (BYTES_PER_CHAR==2)
+/* Swap bytes to proper endian order (could be done externally) */
+#define HTOLS(A) ((((A) >> 8)&0xff)|(((A) & 0xff)<<8))
+#else
+#define HTOLS(A) (A)
+#endif
+   for (i=0;i<nchars;i++)
+      bits->chars[i]=HTOLS(chars[i]);
+
+   bits->nbBits=nchars<<LOG2_BITS_PER_CHAR;
+   bits->charPtr=0;
+   bits->bitPtr=0;
+   bits->overflow=0;
+}
+
+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;i<nchars; i++) 
+       bits->chars[i-bits->charPtr]=bits->chars[i];
+   }
+   bits->nbBits -= bits->charPtr<<LOG2_BITS_PER_CHAR;
+   bits->charPtr=0;
+}
+
+void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes)
+{
+   int i,pos;
+   int nchars = nbytes/BYTES_PER_CHAR;
+
+   if (((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR)+nchars > bits->buf_size)
+   {
+      /* Packet is larger than allocated buffer */
+      if (bits->owner)
+      {
+         char *tmp = (char*)speex_realloc(bits->chars, (bits->nbBits>>LOG2_BITS_PER_CHAR)+nchars+1);
+         if (tmp)
+         {
+            bits->buf_size=(bits->nbBits>>LOG2_BITS_PER_CHAR)+nchars+1;
+            bits->chars=tmp;
+         } else {
+            nchars=bits->buf_size-(bits->nbBits>>LOG2_BITS_PER_CHAR)-1;
+            speex_warning("Could not resize input buffer: truncating oversize input");
+         }
+      } else {
+         speex_warning("Do not own input buffer: truncating oversize input");
+         nchars=bits->buf_size;
+      }
+   }
+
+   speex_bits_flush(bits);
+   pos=bits->nbBits>>LOG2_BITS_PER_CHAR;
+   for (i=0;i<nchars;i++)
+      bits->chars[pos+i]=HTOLS(chars[i]);
+   bits->nbBits+=nchars<<LOG2_BITS_PER_CHAR;
+}
+
+int speex_bits_write(SpeexBits *bits, char *chars, int max_nbytes)
+{
+   int i;
+   int max_nchars = max_nbytes/BYTES_PER_CHAR;
+   int charPtr, bitPtr, nbBits;
+
+   /* Insert terminator, but save the data so we can put it back after */
+   bitPtr=bits->bitPtr;
+   charPtr=bits->charPtr;
+   nbBits=bits->nbBits;
+   speex_bits_insert_terminator(bits);
+   bits->bitPtr=bitPtr;
+   bits->charPtr=charPtr;
+   bits->nbBits=nbBits;
+
+   if (max_nchars > ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR))
+      max_nchars = ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR);
+
+   for (i=0;i<max_nchars;i++)
+      chars[i]=HTOLS(bits->chars[i]);
+   return max_nchars*BYTES_PER_CHAR;
+}
+
+int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes)
+{
+   int max_nchars = max_nbytes/BYTES_PER_CHAR;
+   int i;
+   if (max_nchars > ((bits->nbBits)>>LOG2_BITS_PER_CHAR))
+      max_nchars = ((bits->nbBits)>>LOG2_BITS_PER_CHAR);
+   for (i=0;i<max_nchars;i++)
+      chars[i]=HTOLS(bits->chars[i]);
+
+   if (bits->bitPtr>0)
+      bits->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)
+{
+   unsigned int d=data;
+
+   if (bits->charPtr+((nbBits+bits->bitPtr)>>LOG2_BITS_PER_CHAR) >= bits->buf_size)
+   {
+      speex_notify("Buffer too small to pack bits");
+      if (bits->owner)
+      {
+         int new_nchars = ((bits->buf_size+5)*3)>>1;
+         char *tmp = (char*)speex_realloc(bits->chars, new_nchars);
+         if (tmp)
+         {
+            bits->buf_size=new_nchars;
+            bits->chars=tmp;
+         } else {
+            speex_warning("Could not resize input buffer: not packing");
+            return;
+         }
+      } else {
+         speex_warning("Do not own input buffer: not packing");
+         return;
+      }
+   }
+
+   while(nbBits)
+   {
+      int bit;
+      bit = (d>>(nbBits-1))&1;
+      bits->chars[bits->charPtr] |= bit<<(BITS_PER_CHAR-1-bits->bitPtr);
+      bits->bitPtr++;
+
+      if (bits->bitPtr==BITS_PER_CHAR)
+      {
+         bits->bitPtr=0;
+         bits->charPtr++;
+         bits->chars[bits->charPtr] = 0;
+      }
+      bits->nbBits++;
+      nbBits--;
+   }
+}
+
+int speex_bits_unpack_signed(SpeexBits *bits, int nbBits)
+{
+   unsigned int d=speex_bits_unpack_unsigned(bits,nbBits);
+   /* If number is negative */
+   if (d>>(nbBits-1))
+   {
+      d |= (-1)<<nbBits;
+   }
+   return d;
+}
+
+unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits)
+{
+   unsigned int d=0;
+   if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+nbBits>bits->nbBits)
+      bits->overflow=1;
+   if (bits->overflow)
+      return 0;
+   while(nbBits)
+   {
+      d<<=1;
+      d |= (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1;
+      bits->bitPtr++;
+      if (bits->bitPtr==BITS_PER_CHAR)
+      {
+         bits->bitPtr=0;
+         bits->charPtr++;
+      }
+      nbBits--;
+   }
+   return d;
+}
+
+unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits)
+{
+   unsigned int d=0;
+   int bitPtr, charPtr;
+   char *chars;
+
+   if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+nbBits>bits->nbBits)
+     bits->overflow=1;
+   if (bits->overflow)
+      return 0;
+
+   bitPtr=bits->bitPtr;
+   charPtr=bits->charPtr;
+   chars = bits->chars;
+   while(nbBits)
+   {
+      d<<=1;
+      d |= (chars[charPtr]>>(BITS_PER_CHAR-1 - bitPtr))&1;
+      bitPtr++;
+      if (bitPtr==BITS_PER_CHAR)
+      {
+         bitPtr=0;
+         charPtr++;
+      }
+      nbBits--;
+   }
+   return d;
+}
+
+int speex_bits_peek(SpeexBits *bits)
+{
+   if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+1>bits->nbBits)
+      bits->overflow=1;
+   if (bits->overflow)
+      return 0;
+   return (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1;
+}
+
+void speex_bits_advance(SpeexBits *bits, int n)
+{
+    if (((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+n>bits->nbBits) || bits->overflow){
+      bits->overflow=1;
+      return;
+    }
+   bits->charPtr += (bits->bitPtr+n) >> LOG2_BITS_PER_CHAR; /* divide by BITS_PER_CHAR */
+   bits->bitPtr = (bits->bitPtr+n) & (BITS_PER_CHAR-1);       /* modulo by BITS_PER_CHAR */
+}
+
+int speex_bits_remaining(SpeexBits *bits)
+{
+   if (bits->overflow)
+      return -1;
+   else
+      return bits->nbBits-((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr);
+}
+
+int speex_bits_nbytes(SpeexBits *bits)
+{
+   return ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR);
+}
+
+void speex_bits_insert_terminator(SpeexBits *bits)
+{
+   if (bits->bitPtr)
+      speex_bits_pack(bits, 0, 1);
+   while (bits->bitPtr)
+      speex_bits_pack(bits, 1, 1);
+}
diff --git a/3rdparty/speex/libspeex/cb_search.c b/3rdparty/speex/libspeex/cb_search.c
new file mode 100644
index 0000000..6c4f068
--- /dev/null
+++ b/3rdparty/speex/libspeex/cb_search.c
@@ -0,0 +1,608 @@
+/* Copyright (C) 2002-2006 Jean-Marc Valin 
+   File: cb_search.c
+
+   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 "cb_search.h"
+#include "filters.h"
+#include "stack_alloc.h"
+#include "vq.h"
+#include "misc.h"
+
+#ifdef _USE_SSE
+#include "cb_search_sse.h"
+#elif defined(ARM4_ASM) || defined(ARM5E_ASM)
+#include "cb_search_arm4.h"
+#elif defined(BFIN_ASM)
+#include "cb_search_bfin.h"
+#endif
+
+#ifndef OVERRIDE_COMPUTE_WEIGHTED_CODEBOOK
+static void compute_weighted_codebook(const signed char *shape_cb, const spx_word16_t *r, spx_word16_t *resp, spx_word16_t *resp2, spx_word32_t *E, int shape_cb_size, int subvect_size, char *stack)
+{
+   int i, j, k;
+   VARDECL(spx_word16_t *shape);
+   ALLOC(shape, subvect_size, spx_word16_t);
+   for (i=0;i<shape_cb_size;i++)
+   {
+      spx_word16_t *res;
+      
+      res = resp+i*subvect_size;
+      for (k=0;k<subvect_size;k++)
+         shape[k] = (spx_word16_t)shape_cb[i*subvect_size+k];
+      E[i]=0;
+
+      /* Compute codeword response using convolution with impulse response */
+      for(j=0;j<subvect_size;j++)
+      {
+         spx_word32_t resj=0;
+         spx_word16_t res16;
+         for (k=0;k<=j;k++)
+            resj = MAC16_16(resj,shape[k],r[j-k]);
+#ifdef FIXED_POINT
+         res16 = EXTRACT16(SHR32(resj, 13));
+#else
+         res16 = 0.03125f*resj;
+#endif
+         /* Compute codeword energy */
+         E[i]=MAC16_16(E[i],res16,res16);
+         res[j] = res16;
+         /*printf ("%d\n", (int)res[j]);*/
+      }
+   }
+
+}
+#endif
+
+#ifndef OVERRIDE_TARGET_UPDATE
+static inline void target_update(spx_word16_t *t, spx_word16_t g, spx_word16_t *r, int len)
+{
+   int n;
+   for (n=0;n<len;n++)
+      t[n] = SUB16(t[n],PSHR32(MULT16_16(g,r[n]),13));
+}
+#endif
+
+
+
+static void split_cb_search_shape_sign_N1(
+spx_word16_t target[],			/* target vector */
+spx_coef_t ak[],			/* LPCs for this subframe */
+spx_coef_t awk1[],			/* Weighted LPCs for this subframe */
+spx_coef_t awk2[],			/* Weighted LPCs for this subframe */
+const void *par,                      /* Codebook/search parameters*/
+int   p,                        /* number of LPC coeffs */
+int   nsf,                      /* number of samples in subframe */
+spx_sig_t *exc,
+spx_word16_t *r,
+SpeexBits *bits,
+char *stack,
+int   update_target
+)
+{
+   int i,j,m,q;
+   VARDECL(spx_word16_t *resp);
+#ifdef _USE_SSE
+   VARDECL(__m128 *resp2);
+   VARDECL(__m128 *E);
+#else
+   spx_word16_t *resp2;
+   VARDECL(spx_word32_t *E);
+#endif
+   VARDECL(spx_word16_t *t);
+   VARDECL(spx_sig_t *e);
+   const signed char *shape_cb;
+   int shape_cb_size, subvect_size, nb_subvect;
+   const split_cb_params *params;
+   int best_index;
+   spx_word32_t best_dist;
+   int have_sign;
+   
+   params = (const split_cb_params *) par;
+   subvect_size = params->subvect_size;
+   nb_subvect = params->nb_subvect;
+   shape_cb_size = 1<<params->shape_bits;
+   shape_cb = params->shape_cb;
+   have_sign = params->have_sign;
+   ALLOC(resp, shape_cb_size*subvect_size, spx_word16_t);
+#ifdef _USE_SSE
+   ALLOC(resp2, (shape_cb_size*subvect_size)>>2, __m128);
+   ALLOC(E, shape_cb_size>>2, __m128);
+#else
+   resp2 = resp;
+   ALLOC(E, shape_cb_size, spx_word32_t);
+#endif
+   ALLOC(t, nsf, spx_word16_t);
+   ALLOC(e, nsf, spx_sig_t);
+   
+   /* FIXME: Do we still need to copy the target? */
+   for (i=0;i<nsf;i++)
+      t[i]=target[i];
+
+   compute_weighted_codebook(shape_cb, r, resp, resp2, E, shape_cb_size, subvect_size, stack);
+
+   for (i=0;i<nb_subvect;i++)
+   {
+      spx_word16_t *x=t+subvect_size*i;
+      /*Find new n-best based on previous n-best j*/
+      if (have_sign)
+         vq_nbest_sign(x, resp2, subvect_size, shape_cb_size, E, 1, &best_index, &best_dist, stack);
+      else
+         vq_nbest(x, resp2, subvect_size, shape_cb_size, E, 1, &best_index, &best_dist, stack);
+      
+      speex_bits_pack(bits,best_index,params->shape_bits+have_sign);
+      
+      {
+         int rind;
+         spx_word16_t *res;
+         spx_word16_t sign=1;
+         rind = best_index;
+         if (rind>=shape_cb_size)
+         {
+            sign=-1;
+            rind-=shape_cb_size;
+         }
+         res = resp+rind*subvect_size;
+         if (sign>0)
+            for (m=0;m<subvect_size;m++)
+               t[subvect_size*i+m] = SUB16(t[subvect_size*i+m], res[m]);
+         else
+            for (m=0;m<subvect_size;m++)
+               t[subvect_size*i+m] = ADD16(t[subvect_size*i+m], res[m]);
+
+#ifdef FIXED_POINT
+         if (sign)
+         {
+            for (j=0;j<subvect_size;j++)
+               e[subvect_size*i+j]=SHL32(EXTEND32(shape_cb[rind*subvect_size+j]),SIG_SHIFT-5);
+         } else {
+            for (j=0;j<subvect_size;j++)
+               e[subvect_size*i+j]=NEG32(SHL32(EXTEND32(shape_cb[rind*subvect_size+j]),SIG_SHIFT-5));
+         }
+#else
+         for (j=0;j<subvect_size;j++)
+            e[subvect_size*i+j]=sign*0.03125*shape_cb[rind*subvect_size+j];
+#endif
+      
+      }
+            
+      for (m=0;m<subvect_size;m++)
+      {
+         spx_word16_t g;
+         int rind;
+         spx_word16_t sign=1;
+         rind = best_index;
+         if (rind>=shape_cb_size)
+         {
+            sign=-1;
+            rind-=shape_cb_size;
+         }
+         
+         q=subvect_size-m;
+#ifdef FIXED_POINT
+         g=sign*shape_cb[rind*subvect_size+m];
+#else
+         g=sign*0.03125*shape_cb[rind*subvect_size+m];
+#endif
+         target_update(t+subvect_size*(i+1), g, r+q, nsf-subvect_size*(i+1));
+      }
+   }
+
+   /* Update excitation */
+   /* FIXME: We could update the excitation directly above */
+   for (j=0;j<nsf;j++)
+      exc[j]=ADD32(exc[j],e[j]);
+   
+   /* Update target: only update target if necessary */
+   if (update_target)
+   {
+      VARDECL(spx_word16_t *r2);
+      ALLOC(r2, nsf, spx_word16_t);
+      for (j=0;j<nsf;j++)
+         r2[j] = EXTRACT16(PSHR32(e[j] ,6));
+      syn_percep_zero16(r2, ak, awk1, awk2, r2, nsf,p, stack);
+      for (j=0;j<nsf;j++)
+         target[j]=SUB16(target[j],PSHR16(r2[j],2));
+   }
+}
+
+
+
+void split_cb_search_shape_sign(
+spx_word16_t target[],			/* target vector */
+spx_coef_t ak[],			/* LPCs for this subframe */
+spx_coef_t awk1[],			/* Weighted LPCs for this subframe */
+spx_coef_t awk2[],			/* Weighted LPCs for this subframe */
+const void *par,                      /* Codebook/search parameters*/
+int   p,                        /* number of LPC coeffs */
+int   nsf,                      /* number of samples in subframe */
+spx_sig_t *exc,
+spx_word16_t *r,
+SpeexBits *bits,
+char *stack,
+int   complexity,
+int   update_target
+)
+{
+   int i,j,k,m,n,q;
+   VARDECL(spx_word16_t *resp);
+#ifdef _USE_SSE
+   VARDECL(__m128 *resp2);
+   VARDECL(__m128 *E);
+#else
+   spx_word16_t *resp2;
+   VARDECL(spx_word32_t *E);
+#endif
+   VARDECL(spx_word16_t *t);
+   VARDECL(spx_sig_t *e);
+   VARDECL(spx_word16_t *tmp);
+   VARDECL(spx_word32_t *ndist);
+   VARDECL(spx_word32_t *odist);
+   VARDECL(int *itmp);
+   VARDECL(spx_word16_t **ot2);
+   VARDECL(spx_word16_t **nt2);
+   spx_word16_t **ot, **nt;
+   VARDECL(int **nind);
+   VARDECL(int **oind);
+   VARDECL(int *ind);
+   const signed char *shape_cb;
+   int shape_cb_size, subvect_size, nb_subvect;
+   const split_cb_params *params;
+   int N=2;
+   VARDECL(int *best_index);
+   VARDECL(spx_word32_t *best_dist);
+   VARDECL(int *best_nind);
+   VARDECL(int *best_ntarget);
+   int have_sign;
+   N=complexity;
+   if (N>10)
+      N=10;
+   /* Complexity isn't as important for the codebooks as it is for the pitch */
+   N=(2*N)/3;
+   if (N<1)
+      N=1;
+   if (N==1)
+   {
+      split_cb_search_shape_sign_N1(target,ak,awk1,awk2,par,p,nsf,exc,r,bits,stack,update_target);
+      return;
+   }
+   ALLOC(ot2, N, spx_word16_t*);
+   ALLOC(nt2, N, spx_word16_t*);
+   ALLOC(oind, N, int*);
+   ALLOC(nind, N, int*);
+
+   params = (const split_cb_params *) par;
+   subvect_size = params->subvect_size;
+   nb_subvect = params->nb_subvect;
+   shape_cb_size = 1<<params->shape_bits;
+   shape_cb = params->shape_cb;
+   have_sign = params->have_sign;
+   ALLOC(resp, shape_cb_size*subvect_size, spx_word16_t);
+#ifdef _USE_SSE
+   ALLOC(resp2, (shape_cb_size*subvect_size)>>2, __m128);
+   ALLOC(E, shape_cb_size>>2, __m128);
+#else
+   resp2 = resp;
+   ALLOC(E, shape_cb_size, spx_word32_t);
+#endif
+   ALLOC(t, nsf, spx_word16_t);
+   ALLOC(e, nsf, spx_sig_t);
+   ALLOC(ind, nb_subvect, int);
+
+   ALLOC(tmp, 2*N*nsf, spx_word16_t);
+   for (i=0;i<N;i++)
+   {
+      ot2[i]=tmp+2*i*nsf;
+      nt2[i]=tmp+(2*i+1)*nsf;
+   }
+   ot=ot2;
+   nt=nt2;
+   ALLOC(best_index, N, int);
+   ALLOC(best_dist, N, spx_word32_t);
+   ALLOC(best_nind, N, int);
+   ALLOC(best_ntarget, N, int);
+   ALLOC(ndist, N, spx_word32_t);
+   ALLOC(odist, N, spx_word32_t);
+   
+   ALLOC(itmp, 2*N*nb_subvect, int);
+   for (i=0;i<N;i++)
+   {
+      nind[i]=itmp+2*i*nb_subvect;
+      oind[i]=itmp+(2*i+1)*nb_subvect;
+   }
+   
+   for (i=0;i<nsf;i++)
+      t[i]=target[i];
+
+   for (j=0;j<N;j++)
+      speex_move(&ot[j][0], t, nsf*sizeof(spx_word16_t));
+
+   /* Pre-compute codewords response and energy */
+   compute_weighted_codebook(shape_cb, r, resp, resp2, E, shape_cb_size, subvect_size, stack);
+
+   for (j=0;j<N;j++)
+      odist[j]=0;
+   
+   /*For all subvectors*/
+   for (i=0;i<nb_subvect;i++)
+   {
+      /*"erase" nbest list*/
+      for (j=0;j<N;j++)
+         ndist[j]=VERY_LARGE32;
+
+      /*For all n-bests of previous subvector*/
+      for (j=0;j<N;j++)
+      {
+         spx_word16_t *x=ot[j]+subvect_size*i;
+         spx_word32_t tener = 0;
+         for (m=0;m<subvect_size;m++)
+            tener = MAC16_16(tener, x[m],x[m]);
+#ifdef FIXED_POINT
+         tener = SHR32(tener,1);
+#else
+         tener *= .5;
+#endif
+         /*Find new n-best based on previous n-best j*/
+         if (have_sign)
+            vq_nbest_sign(x, resp2, subvect_size, shape_cb_size, E, N, best_index, best_dist, stack);
+         else
+            vq_nbest(x, resp2, subvect_size, shape_cb_size, E, N, best_index, best_dist, stack);
+
+         /*For all new n-bests*/
+         for (k=0;k<N;k++)
+         {
+            /* Compute total distance (including previous sub-vectors */
+            spx_word32_t err = ADD32(ADD32(odist[j],best_dist[k]),tener);
+            
+            /*update n-best list*/
+            if (err<ndist[N-1])
+            {
+               for (m=0;m<N;m++)
+               {
+                  if (err < ndist[m])
+                  {
+                     for (n=N-1;n>m;n--)
+                     {
+                        ndist[n] = ndist[n-1];
+                        best_nind[n] = best_nind[n-1];
+                        best_ntarget[n] = best_ntarget[n-1];
+                     }
+                     ndist[m] = err;
+                     best_nind[n] = best_index[k];
+                     best_ntarget[n] = j;
+                     break;
+                  }
+               }
+            }
+         }
+         if (i==0)
+            break;
+      }
+      for (j=0;j<N;j++)
+      {
+         /*previous target (we don't care what happened before*/
+         for (m=(i+1)*subvect_size;m<nsf;m++)
+            nt[j][m]=ot[best_ntarget[j]][m];
+         
+         /* New code: update the rest of the target only if it's worth it */
+         for (m=0;m<subvect_size;m++)
+         {
+            spx_word16_t g;
+            int rind;
+            spx_word16_t sign=1;
+            rind = best_nind[j];
+            if (rind>=shape_cb_size)
+            {
+               sign=-1;
+               rind-=shape_cb_size;
+            }
+
+            q=subvect_size-m;
+#ifdef FIXED_POINT
+            g=sign*shape_cb[rind*subvect_size+m];
+#else
+            g=sign*0.03125*shape_cb[rind*subvect_size+m];
+#endif
+            target_update(nt[j]+subvect_size*(i+1), g, r+q, nsf-subvect_size*(i+1));
+         }
+
+         for (q=0;q<nb_subvect;q++)
+            nind[j][q]=oind[best_ntarget[j]][q];
+         nind[j][i]=best_nind[j];
+      }
+
+      /*update old-new data*/
+      /* just swap pointers instead of a long copy */
+      {
+         spx_word16_t **tmp2;
+         tmp2=ot;
+         ot=nt;
+         nt=tmp2;
+      }
+      for (j=0;j<N;j++)
+         for (m=0;m<nb_subvect;m++)
+            oind[j][m]=nind[j][m];
+      for (j=0;j<N;j++)
+         odist[j]=ndist[j];
+   }
+
+   /*save indices*/
+   for (i=0;i<nb_subvect;i++)
+   {
+      ind[i]=nind[0][i];
+      speex_bits_pack(bits,ind[i],params->shape_bits+have_sign);
+   }
+   
+   /* Put everything back together */
+   for (i=0;i<nb_subvect;i++)
+   {
+      int rind;
+      spx_word16_t sign=1;
+      rind = ind[i];
+      if (rind>=shape_cb_size)
+      {
+         sign=-1;
+         rind-=shape_cb_size;
+      }
+#ifdef FIXED_POINT
+      if (sign==1)
+      {
+         for (j=0;j<subvect_size;j++)
+            e[subvect_size*i+j]=SHL32(EXTEND32(shape_cb[rind*subvect_size+j]),SIG_SHIFT-5);
+      } else {
+         for (j=0;j<subvect_size;j++)
+            e[subvect_size*i+j]=NEG32(SHL32(EXTEND32(shape_cb[rind*subvect_size+j]),SIG_SHIFT-5));
+      }
+#else
+      for (j=0;j<subvect_size;j++)
+         e[subvect_size*i+j]=sign*0.03125*shape_cb[rind*subvect_size+j];
+#endif
+   }   
+   /* Update excitation */
+   for (j=0;j<nsf;j++)
+      exc[j]=ADD32(exc[j],e[j]);
+   
+   /* Update target: only update target if necessary */
+   if (update_target)
+   {
+      VARDECL(spx_word16_t *r2);
+      ALLOC(r2, nsf, spx_word16_t);
+      for (j=0;j<nsf;j++)
+         r2[j] = EXTRACT16(PSHR32(e[j] ,6));
+      syn_percep_zero16(r2, ak, awk1, awk2, r2, nsf,p, stack);
+      for (j=0;j<nsf;j++)
+         target[j]=SUB16(target[j],PSHR16(r2[j],2));
+   }
+}
+
+
+void split_cb_shape_sign_unquant(
+spx_sig_t *exc,
+const void *par,                      /* non-overlapping codebook */
+int   nsf,                      /* number of samples in subframe */
+SpeexBits *bits,
+char *stack,
+spx_int32_t *seed
+)
+{
+   int i,j;
+   VARDECL(int *ind);
+   VARDECL(int *signs);
+   const signed char *shape_cb;
+   int shape_cb_size, subvect_size, nb_subvect;
+   const split_cb_params *params;
+   int have_sign;
+
+   params = (const split_cb_params *) par;
+   subvect_size = params->subvect_size;
+   nb_subvect = params->nb_subvect;
+   shape_cb_size = 1<<params->shape_bits;
+   shape_cb = params->shape_cb;
+   have_sign = params->have_sign;
+
+   ALLOC(ind, nb_subvect, int);
+   ALLOC(signs, nb_subvect, int);
+
+   /* Decode codewords and gains */
+   for (i=0;i<nb_subvect;i++)
+   {
+      if (have_sign)
+         signs[i] = speex_bits_unpack_unsigned(bits, 1);
+      else
+         signs[i] = 0;
+      ind[i] = speex_bits_unpack_unsigned(bits, params->shape_bits);
+   }
+   /* Compute decoded excitation */
+   for (i=0;i<nb_subvect;i++)
+   {
+      spx_word16_t s=1;
+      if (signs[i])
+         s=-1;
+#ifdef FIXED_POINT
+      if (s==1)
+      {
+         for (j=0;j<subvect_size;j++)
+            exc[subvect_size*i+j]=SHL32(EXTEND32(shape_cb[ind[i]*subvect_size+j]),SIG_SHIFT-5);
+      } else {
+         for (j=0;j<subvect_size;j++)
+            exc[subvect_size*i+j]=NEG32(SHL32(EXTEND32(shape_cb[ind[i]*subvect_size+j]),SIG_SHIFT-5));
+      }
+#else
+      for (j=0;j<subvect_size;j++)
+         exc[subvect_size*i+j]+=s*0.03125*shape_cb[ind[i]*subvect_size+j];      
+#endif
+   }
+}
+
+void noise_codebook_quant(
+spx_word16_t target[],			/* target vector */
+spx_coef_t ak[],			/* LPCs for this subframe */
+spx_coef_t awk1[],			/* Weighted LPCs for this subframe */
+spx_coef_t awk2[],			/* Weighted LPCs for this subframe */
+const void *par,                      /* Codebook/search parameters*/
+int   p,                        /* number of LPC coeffs */
+int   nsf,                      /* number of samples in subframe */
+spx_sig_t *exc,
+spx_word16_t *r,
+SpeexBits *bits,
+char *stack,
+int   complexity,
+int   update_target
+)
+{
+   int i;
+   VARDECL(spx_word16_t *tmp);
+   ALLOC(tmp, nsf, spx_word16_t);
+   residue_percep_zero16(target, ak, awk1, awk2, tmp, nsf, p, stack);
+
+   for (i=0;i<nsf;i++)
+      exc[i]+=SHL32(EXTEND32(tmp[i]),8);
+   for (i=0;i<nsf;i++)
+      target[i]=0;
+}
+
+
+void noise_codebook_unquant(
+spx_sig_t *exc,
+const void *par,                      /* non-overlapping codebook */
+int   nsf,                      /* number of samples in subframe */
+SpeexBits *bits,
+char *stack,
+spx_int32_t *seed
+)
+{
+   int i;
+   /* FIXME: This is bad, but I don't think the function ever gets called anyway */
+   for (i=0;i<nsf;i++)
+      exc[i]=SHL32(EXTEND32(speex_rand(1, seed)),SIG_SHIFT);
+}
diff --git a/3rdparty/speex/libspeex/cb_search.h b/3rdparty/speex/libspeex/cb_search.h
new file mode 100644
index 0000000..fd5c110
--- /dev/null
+++ b/3rdparty/speex/libspeex/cb_search.h
@@ -0,0 +1,103 @@
+/* Copyright (C) 2002 Jean-Marc Valin & David Rowe */
+/**
+   @file cb_search.h
+   @brief Overlapped codebook search
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CB_SEARCH_H
+#define CB_SEARCH_H
+
+#include <speex/speex_bits.h>
+#include "misc.h"
+
+/** Split codebook parameters. */
+typedef struct split_cb_params {
+   int     subvect_size;
+   int     nb_subvect;
+   const signed char  *shape_cb;
+   int     shape_bits;
+   int     have_sign;
+} split_cb_params;
+
+
+void split_cb_search_shape_sign(
+spx_word16_t target[],             /* target vector */
+spx_coef_t ak[],                /* LPCs for this subframe */
+spx_coef_t awk1[],              /* Weighted LPCs for this subframe */
+spx_coef_t awk2[],              /* Weighted LPCs for this subframe */
+const void *par,                /* Codebook/search parameters */
+int   p,                        /* number of LPC coeffs */
+int   nsf,                      /* number of samples in subframe */
+spx_sig_t *exc,
+spx_word16_t *r,
+SpeexBits *bits,
+char *stack,
+int   complexity,
+int   update_target
+);
+
+void split_cb_shape_sign_unquant(
+spx_sig_t *exc,
+const void *par,                /* non-overlapping codebook */
+int   nsf,                      /* number of samples in subframe */
+SpeexBits *bits,
+char *stack,
+spx_int32_t *seed
+);
+
+
+void noise_codebook_quant(
+spx_word16_t target[],             /* target vector */
+spx_coef_t ak[],                /* LPCs for this subframe */
+spx_coef_t awk1[],              /* Weighted LPCs for this subframe */
+spx_coef_t awk2[],              /* Weighted LPCs for this subframe */
+const void *par,                /* Codebook/search parameters */
+int   p,                        /* number of LPC coeffs */
+int   nsf,                      /* number of samples in subframe */
+spx_sig_t *exc,
+spx_word16_t *r,
+SpeexBits *bits,
+char *stack,
+int   complexity,
+int   update_target
+);
+
+
+void noise_codebook_unquant(
+spx_sig_t *exc,
+const void *par,                /* non-overlapping codebook */
+int   nsf,                      /* number of samples in subframe */
+SpeexBits *bits,
+char *stack,
+spx_int32_t *seed
+);
+
+#endif
diff --git a/3rdparty/speex/libspeex/cb_search_arm4.h b/3rdparty/speex/libspeex/cb_search_arm4.h
new file mode 100644
index 0000000..19b752a
--- /dev/null
+++ b/3rdparty/speex/libspeex/cb_search_arm4.h
@@ -0,0 +1,137 @@
+/* Copyright (C) 2004 Jean-Marc Valin */
+/**
+   @file cb_search_arm4.h
+   @brief Fixed codebook functions (ARM4 version)
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* This optimization is temporaly disabled until it is fixed to account for the fact 
+   that "r" is now a 16-bit array */
+#if 0
+#define OVERRIDE_COMPUTE_WEIGHTED_CODEBOOK
+static void compute_weighted_codebook(const signed char *shape_cb, const spx_word16_t *r, spx_word16_t *resp, spx_word16_t *resp2, spx_word32_t *E, int shape_cb_size, int subvect_size, char *stack)
+{
+   int i, j, k;
+  //const signed char *shape;
+   for (i=0;i<shape_cb_size;i+=4)
+   {
+
+      //shape = shape_cb;
+      E[0]=0;
+      E[1]=0;
+      E[2]=0;
+      E[3]=0;
+
+      /* Compute codeword response using convolution with impulse response */
+      for(j=0;j<subvect_size;j++)
+      {
+#if 1
+          spx_word16_t *res;
+          res = resp+j;
+          spx_word32_t resj0,resj1,resj2,resj3;
+          spx_word32_t dead1, dead2, dead3, dead4, dead5, dead6, dead7, dead8;
+          __asm__ __volatile__ (
+                "mov %0, #0 \n\t"
+                "mov %1, #0 \n\t"
+                "mov %2, #0 \n\t"
+                "mov %3, #0 \n\t"
+                ".weighted%=: \n\t"
+                "ldrsb %8, [%6] \n\t"
+                "ldr %10, [%5], #-4 \n\t"
+                "mov %9, %6 \n\t"
+                "ldrsb %11, [%9, %7]! \n\t"
+                "mla %0, %10, %8, %0 \n\t"
+                "ldrsb %8, [%9, %7]! \n\t"
+                "mla %1, %10, %11, %1 \n\t"
+                "ldrsb %11, [%9, %7]! \n\t"
+                "mla %2, %10, %8, %2 \n\t"
+                "subs %4, %4, #1 \n\t"
+                "mla %3, %10, %11, %3 \n\t"
+                "add %6, %6, #1 \n\t"
+                "bne .weighted%= \n\t"
+            : "=r" (resj0), "=r" (resj1), "=r" (resj2), "=r" (resj3),
+          "=r" (dead1), "=r" (dead2), "=r" (dead3), "=r" (dead4),
+          "=r" (dead5), "=r" (dead6), "=r" (dead7), "=r" (dead8)
+            : "4" (j+1), "5" (r+j), "6" (shape_cb), "7" (subvect_size)
+            : "cc", "memory");
+#else
+          spx_word16_t *res;
+          res = resp+j;
+          spx_word32_t resj0=0;
+          spx_word32_t resj1=0;
+          spx_word32_t resj2=0;
+          spx_word32_t resj3=0;
+          for (k=0;k<=j;k++)
+          {
+             const signed char *shape=shape_cb+k;
+             resj0 = MAC16_16(resj0,*shape,r[j-k]);
+             shape += subvect_size;
+             resj1 = MAC16_16(resj1,*shape,r[j-k]);
+             shape += subvect_size;
+             resj2 = MAC16_16(resj2,*shape,r[j-k]);
+             shape += subvect_size;
+             resj3 = MAC16_16(resj3,*shape,r[j-k]);
+             shape += subvect_size;
+          }
+#endif
+
+#ifdef FIXED_POINT
+          resj0 = SHR(resj0, 11);
+          resj1 = SHR(resj1, 11);
+          resj2 = SHR(resj2, 11);
+          resj3 = SHR(resj3, 11);
+#else
+          resj0 *= 0.03125;
+          resj1 *= 0.03125;
+          resj2 *= 0.03125;
+          resj3 *= 0.03125;
+#endif
+
+          /* Compute codeword energy */
+          E[0]=ADD32(E[0],MULT16_16(resj0,resj0));
+          E[1]=ADD32(E[1],MULT16_16(resj1,resj1));
+          E[2]=ADD32(E[2],MULT16_16(resj2,resj2));
+          E[3]=ADD32(E[3],MULT16_16(resj3,resj3));
+          *res = resj0;
+          res += subvect_size;
+          *res = resj1;
+          res += subvect_size;
+          *res = resj2;
+          res += subvect_size;
+          *res = resj3;
+          res += subvect_size;
+      }
+      resp += subvect_size<<2;
+      shape_cb += subvect_size<<2;
+      E+=4;
+   }
+
+}
+#endif
diff --git a/3rdparty/speex/libspeex/cb_search_bfin.h b/3rdparty/speex/libspeex/cb_search_bfin.h
new file mode 100644
index 0000000..ae9cf83
--- /dev/null
+++ b/3rdparty/speex/libspeex/cb_search_bfin.h
@@ -0,0 +1,112 @@
+/* Copyright (C) 2005 Analog Devices */
+/**
+   @author Jean-Marc Valin 
+   @file cb_search_bfin.h
+   @brief Fixed codebook functions (Blackfin version)
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define OVERRIDE_COMPUTE_WEIGHTED_CODEBOOK 
+void compute_weighted_codebook(const signed char *shape_cb, const spx_word16_t *r, spx_word16_t *resp, spx_word16_t *resp2, spx_word32_t *E, int shape_cb_size, int subvect_size, char *stack)
+{
+   int i;
+   for (i=0;i<shape_cb_size;i++)
+   {
+      __asm__ __volatile__ (
+         "P0 = %0;\n\t"
+         "LC0 = P0;\n\t"
+         "P1 = %1;\n\t"
+         "P2 = %2;\n\t"
+         "P3 = %3;\n\t"
+         "P0 = 1;\n\t"
+         "L0 = 0;\n\t"
+         "L1 = 0;\n\t"
+         "R2 = 0;\n\t"
+         "A1 = 0;\n\t"
+         "LOOP outter%= LC0;\n\t"
+         "LOOP_BEGIN outter%=;\n\t"
+            "A0 = 0;\n\t"
+            "P4 = P1;\n\t"
+            "I1 = P2;\n\t"
+            "R0 = B[P4++] (X) || R1.L = W[I1--];\n\t"
+            "LOOP inner%= LC1 = P0;\n\t"
+            "LOOP_BEGIN inner%=;\n\t"
+               "A0 += R0.L*R1.L (IS) || R0 = B[P4++] (X) || R1.L = W[I1--];\n\t"
+            "LOOP_END inner%=;\n\t"
+            "R0 = A0;\n\t"
+            "R0 >>>= 13;\n\t"
+            "A1 += R0.L*R0.L (IS);\n\t"
+            "W[P3++] = R0;\n\t"
+            "P0 += 1;\n\t"
+            "P2 += 2;\n\t"
+         "LOOP_END outter%=;\n\t"
+         "P4 = %4;\n\t"
+         "R1 = A1;\n\t"
+         "[P4] = R1;\n\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"
+#if !(__GNUC__ == 3)
+         , "LC0", "LC1" /* gcc 3.4 doesn't know about LC registers */
+#endif
+      );
+      shape_cb += subvect_size;
+      resp += subvect_size;
+      E++;
+   }
+}
+
+#define OVERRIDE_TARGET_UPDATE
+static inline void target_update(spx_word16_t *t, spx_word16_t g, spx_word16_t *r, int len)
+{
+   if (!len)
+      return;
+   __asm__ __volatile__
+         (
+         "I0 = %0;\n\t"
+         "I1 = %1;\n\t"
+         "L0 = 0;\n\t"
+         "L1 = 0;\n\t"
+         "R2 = 4096;\n\t"
+         "LOOP tupdate%= LC0 = %3;\n\t"
+         "LOOP_BEGIN tupdate%=;\n\t"
+            "R0.L = W[I0] || R1.L = W[I1++];\n\t"
+            "R1 = (A1 = R1.L*%2.L) (IS);\n\t"
+            "R1 = R1 + R2;\n\t"
+            "R1 >>>= 13;\n\t"
+            "R0.L = R0.L - R1.L;\n\t"
+            "W[I0++] = R0.L;\n\t"
+         "LOOP_END tupdate%=;\n\t"
+   :
+   : "a" (t), "a" (r), "d" (g), "a" (len)
+   : "R0", "R1", "R2", "A1", "I0", "I1", "L0", "L1"
+         );
+}
diff --git a/3rdparty/speex/libspeex/cb_search_sse.h b/3rdparty/speex/libspeex/cb_search_sse.h
new file mode 100644
index 0000000..8b03968
--- /dev/null
+++ b/3rdparty/speex/libspeex/cb_search_sse.h
@@ -0,0 +1,84 @@
+/* Copyright (C) 2004 Jean-Marc Valin */
+/**
+   @file cb_search_sse.h
+   @brief Fixed codebook functions (SSE version)
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <xmmintrin.h>
+
+static inline void _spx_mm_getr_ps (__m128 U, float *__Z, float *__Y, float *__X, float *__W)
+{
+  union {
+    float __a[4];
+    __m128 __v;
+  } __u;
+  
+  __u.__v = U;
+
+  *__Z = __u.__a[0];
+  *__Y = __u.__a[1];
+  *__X = __u.__a[2];
+  *__W = __u.__a[3];
+
+}
+
+#define OVERRIDE_COMPUTE_WEIGHTED_CODEBOOK
+static void compute_weighted_codebook(const signed char *shape_cb, const spx_sig_t *_r, float *resp, __m128 *resp2, __m128 *E, int shape_cb_size, int subvect_size, char *stack)
+{
+   int i, j, k;
+   __m128 resj, EE;
+   VARDECL(__m128 *r);
+   VARDECL(__m128 *shape);
+   ALLOC(r, subvect_size, __m128);
+   ALLOC(shape, subvect_size, __m128);
+   for(j=0;j<subvect_size;j++)
+      r[j] = _mm_load_ps1(_r+j);
+   for (i=0;i<shape_cb_size;i+=4)
+   {
+      float *_res = resp+i*subvect_size;
+      const signed char *_shape = shape_cb+i*subvect_size;
+      EE = _mm_setzero_ps();
+      for(j=0;j<subvect_size;j++)
+      {
+         shape[j] = _mm_setr_ps(0.03125*_shape[j], 0.03125*_shape[subvect_size+j], 0.03125*_shape[2*subvect_size+j], 0.03125*_shape[3*subvect_size+j]);
+      }
+      for(j=0;j<subvect_size;j++)
+      {
+         resj = _mm_setzero_ps();
+         for (k=0;k<=j;k++)
+            resj = _mm_add_ps(resj, _mm_mul_ps(shape[k],r[j-k]));
+         _spx_mm_getr_ps(resj, _res+j, _res+subvect_size+j, _res+2*subvect_size+j, _res+3*subvect_size+j);
+         *resp2++ = resj;
+         EE = _mm_add_ps(EE, _mm_mul_ps(resj, resj));
+      }
+      E[i>>2] = EE;
+   }
+}
diff --git a/3rdparty/speex/libspeex/echo_diagnostic.m b/3rdparty/speex/libspeex/echo_diagnostic.m
new file mode 100644
index 0000000..aebf390
--- /dev/null
+++ b/3rdparty/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/3rdparty/speex/libspeex/exc_10_16_table.c b/3rdparty/speex/libspeex/exc_10_16_table.c
new file mode 100644
index 0000000..98ae357
--- /dev/null
+++ b/3rdparty/speex/libspeex/exc_10_16_table.c
@@ -0,0 +1,50 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: exc_10_16_table.c
+   Codebook for excitation in narrowband CELP mode (3200 bps)
+
+   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.
+*/
+
+
+const signed char exc_10_16_table[160] = {
+22,39,14,44,11,35,-2,23,-4,6,
+46,-28,13,-27,-23,12,4,20,-5,9,
+37,-18,-23,23,0,9,-6,-20,4,-1,
+-17,-5,-4,17,0,1,9,-2,1,2,
+2,-12,8,-25,39,15,9,16,-55,-11,
+9,11,5,10,-2,-60,8,13,-6,11,
+-16,27,-47,-12,11,1,16,-7,9,-3,
+-29,9,-14,25,-19,34,36,12,40,-10,
+-3,-24,-14,-37,-21,-35,-2,-36,3,-6,
+67,28,6,-17,-3,-12,-16,-15,-17,-7,
+-59,-36,-13,1,7,1,2,10,2,11,
+13,10,8,-2,7,3,5,4,2,2,
+-3,-8,4,-5,6,7,-42,15,35,-2,
+-46,38,28,-20,-9,1,7,-3,0,-2,
+0,0,0,0,0,0,0,0,0,0,
+-15,-28,52,32,5,-5,-17,-20,-10,-1};
diff --git a/3rdparty/speex/libspeex/exc_10_32_table.c b/3rdparty/speex/libspeex/exc_10_32_table.c
new file mode 100644
index 0000000..1ee56a2
--- /dev/null
+++ b/3rdparty/speex/libspeex/exc_10_32_table.c
@@ -0,0 +1,66 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: exc_10_32_table.c
+   Codebook for excitation in narrowband CELP mode (4000 bps)
+
+   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.
+*/
+
+
+const signed char exc_10_32_table[320] = {
+7,17,17,27,25,22,12,4,-3,0,
+28,-36,39,-24,-15,3,-9,15,-5,10,
+31,-28,11,31,-21,9,-11,-11,-2,-7,
+-25,14,-22,31,4,-14,19,-12,14,-5,
+4,-7,4,-5,9,0,-2,42,-47,-16,
+1,8,0,9,23,-57,0,28,-11,6,
+-31,55,-45,3,-5,4,2,-2,4,-7,
+-3,6,-2,7,-3,12,5,8,54,-10,
+8,-7,-8,-24,-25,-27,-14,-5,8,5,
+44,23,5,-9,-11,-11,-13,-9,-12,-8,
+-29,-8,-22,6,-15,3,-12,-1,-5,-3,
+34,-1,29,-16,17,-4,12,2,1,4,
+-2,-4,2,-1,11,-3,-52,28,30,-9,
+-32,25,44,-20,-24,4,6,-1,0,0,
+0,0,0,0,0,0,0,0,0,0,
+-25,-10,22,29,13,-13,-22,-13,-4,0,
+-4,-16,10,15,-36,-24,28,25,-1,-3,
+66,-33,-11,-15,6,0,3,4,-2,5,
+24,-20,-47,29,19,-2,-4,-1,0,-1,
+-2,3,1,8,-11,5,5,-57,28,28,
+0,-16,4,-4,12,-6,-1,2,-20,61,
+-9,24,-22,-42,29,6,17,8,4,2,
+-65,15,8,10,5,6,5,3,2,-2,
+-3,5,-9,4,-5,23,13,23,-3,-63,
+3,-5,-4,-6,0,-3,23,-36,-46,9,
+5,5,8,4,9,-5,1,-3,10,1,
+-6,10,-11,24,-47,31,22,-12,14,-10,
+6,11,-7,-7,7,-31,51,-12,-6,7,
+6,-17,9,-11,-20,52,-19,3,-6,-6,
+-8,-5,23,-41,37,1,-21,10,-14,8,
+7,5,-15,-15,23,39,-26,-33,7,2,
+-32,-30,-21,-8,4,12,17,15,14,11};
diff --git a/3rdparty/speex/libspeex/exc_20_32_table.c b/3rdparty/speex/libspeex/exc_20_32_table.c
new file mode 100644
index 0000000..e4098b8
--- /dev/null
+++ b/3rdparty/speex/libspeex/exc_20_32_table.c
@@ -0,0 +1,66 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: exc_20_32_table.c
+   Codebook for excitation in narrowband CELP mode (2000 bps)
+
+   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.
+*/
+
+
+const signed char exc_20_32_table[640] = {
+12,32,25,46,36,33,9,14,-3,6,1,-8,0,-10,-5,-7,-7,-7,-5,-5,
+31,-27,24,-32,-4,10,-11,21,-3,19,23,-9,22,24,-10,-1,-10,-13,-7,-11,
+42,-33,31,19,-8,0,-10,-16,1,-21,-17,10,-8,14,8,4,11,-2,5,-2,
+-33,11,-16,33,11,-4,9,-4,11,2,6,-5,8,-5,11,-4,-6,26,-36,-16,
+0,4,-2,-8,12,6,-1,34,-46,-22,9,9,21,9,5,-66,-5,26,2,10,
+13,2,19,9,12,-81,3,13,13,0,-14,22,-35,6,-7,-4,6,-6,10,-6,
+-31,38,-33,0,-10,-11,5,-12,12,-17,5,0,-6,13,-9,10,8,25,33,2,
+-12,8,-6,10,-2,21,7,17,43,5,11,-7,-9,-20,-36,-20,-23,-4,-4,-3,
+27,-9,-9,-49,-39,-38,-11,-9,6,5,23,25,5,3,3,4,1,2,-3,-1,
+87,39,17,-21,-9,-19,-9,-15,-13,-14,-17,-11,-10,-11,-8,-6,-1,-3,-3,-1,
+-54,-34,-27,-8,-11,-4,-5,0,0,4,8,6,9,7,9,7,6,5,5,5,
+48,10,19,-10,12,-1,9,-3,2,5,-3,2,-2,-2,0,-2,-26,6,9,-7,
+-16,-9,2,7,7,-5,-43,11,22,-11,-9,34,37,-15,-13,-6,1,-1,1,1,
+-64,56,52,-11,-27,5,4,3,1,2,1,3,-1,-4,-4,-10,-7,-4,-4,2,
+-1,-7,-7,-12,-10,-15,-9,-5,-5,-11,-16,-13,6,16,4,-13,-16,-10,-4,2,
+-47,-13,25,47,19,-14,-20,-8,-17,0,-3,-13,1,6,-17,-14,15,1,10,6,
+-24,0,-10,19,-69,-8,14,49,17,-5,33,-29,3,-4,0,2,-8,5,-6,2,
+120,-56,-12,-47,23,-9,6,-5,1,2,-5,1,-10,4,-1,-1,4,-1,0,-3,
+30,-52,-67,30,22,11,-1,-4,3,0,7,2,0,1,-10,-4,-8,-13,5,1,
+1,-1,5,13,-9,-3,-10,-62,22,48,-4,-6,2,3,5,1,1,4,1,13,
+3,-20,10,-9,13,-2,-4,9,-20,44,-1,20,-32,-67,19,0,28,11,8,2,
+-11,15,-19,-53,31,2,34,10,6,-4,-58,8,10,13,14,1,12,2,0,0,
+-128,37,-8,44,-9,26,-3,18,2,6,11,-1,9,1,5,3,0,1,1,2,
+12,3,-2,-3,7,25,9,18,-6,-37,3,-8,-16,3,-10,-7,17,-34,-44,11,
+17,-15,-3,-16,-1,-13,11,-46,-65,-2,8,13,2,4,4,5,15,5,9,6,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+-9,19,-12,12,-28,38,29,-1,12,2,5,23,-10,3,4,-15,21,-4,3,3,
+6,17,-9,-4,-8,-20,26,5,-10,6,1,-19,18,-15,-12,47,-6,-2,-7,-9,
+-1,-17,-2,-2,-14,30,-14,2,-7,-4,-1,-12,11,-25,16,-3,-12,11,-7,7,
+-17,1,19,-28,31,-7,-10,7,-10,3,12,5,-16,6,24,41,-29,-54,0,1,
+7,-1,5,-6,13,10,-4,-8,8,-9,-27,-53,-38,-1,10,19,17,16,12,12,
+0,3,-7,-4,13,12,-31,-14,6,-5,3,5,17,43,50,25,10,1,-6,-2};
diff --git a/3rdparty/speex/libspeex/exc_5_256_table.c b/3rdparty/speex/libspeex/exc_5_256_table.c
new file mode 100644
index 0000000..4137996
--- /dev/null
+++ b/3rdparty/speex/libspeex/exc_5_256_table.c
@@ -0,0 +1,290 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: exc_5_256_table.c
+   Codebook for excitation in narrowband CELP mode (12800 bps)
+
+   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.
+*/
+
+
+const signed char exc_5_256_table[1280] = {
+-8,-37,5,-43,5,
+73,61,39,12,-3,
+-61,-32,2,42,30,
+-3,17,-27,9,34,
+20,-1,-5,2,23,
+-7,-46,26,53,-47,
+20,-2,-33,-89,-51,
+-64,27,11,15,-34,
+-5,-56,25,-9,-1,
+-29,1,40,67,-23,
+-16,16,33,19,7,
+14,85,22,-10,-10,
+-12,-7,-1,52,89,
+29,11,-20,-37,-46,
+-15,17,-24,-28,24,
+2,1,0,23,-101,
+23,14,-1,-23,-18,
+9,5,-13,38,1,
+-28,-28,4,27,51,
+-26,34,-40,35,47,
+54,38,-54,-26,-6,
+42,-25,13,-30,-36,
+18,41,-4,-33,23,
+-32,-7,-4,51,-3,
+17,-52,56,-47,36,
+-2,-21,36,10,8,
+-33,31,19,9,-5,
+-40,10,-9,-21,19,
+18,-78,-18,-5,0,
+-26,-36,-47,-51,-44,
+18,40,27,-2,29,
+49,-26,2,32,-54,
+30,-73,54,3,-5,
+36,22,53,10,-1,
+-84,-53,-29,-5,3,
+-44,53,-51,4,22,
+71,-35,-1,33,-5,
+-27,-7,36,17,-23,
+-39,16,-9,-55,-15,
+-20,39,-35,6,-39,
+-14,18,48,-64,-17,
+-15,9,39,81,37,
+-68,37,47,-21,-6,
+-104,13,6,9,-2,
+35,8,-23,18,42,
+45,21,33,-5,-49,
+9,-6,-43,-56,39,
+2,-16,-25,87,1,
+-3,-9,17,-25,-11,
+-9,-1,10,2,-14,
+-14,4,-1,-10,28,
+-23,40,-32,26,-9,
+26,4,-27,-23,3,
+42,-60,1,49,-3,
+27,10,-52,-40,-2,
+18,45,-23,17,-44,
+3,-3,17,-46,52,
+-40,-47,25,75,31,
+-49,53,30,-30,-32,
+-36,38,-6,-15,-16,
+54,-27,-48,3,38,
+-29,-32,-22,-14,-4,
+-23,-13,32,-39,9,
+8,-45,-13,34,-16,
+49,40,32,31,28,
+23,23,32,47,59,
+-68,8,62,44,25,
+-14,-24,-65,-16,36,
+67,-25,-38,-21,4,
+-33,-2,42,5,-63,
+40,11,26,-42,-23,
+-61,79,-31,23,-20,
+10,-32,53,-25,-36,
+10,-26,-5,3,0,
+-71,5,-10,-37,1,
+-24,21,-54,-17,1,
+-29,-25,-15,-27,32,
+68,45,-16,-37,-18,
+-5,1,0,-77,71,
+-6,3,-20,71,-67,
+29,-35,10,-30,19,
+4,16,17,5,0,
+-14,19,2,28,26,
+59,3,2,24,39,
+55,-50,-45,-18,-17,
+33,-35,14,-1,1,
+8,87,-35,-29,0,
+-27,13,-7,23,-13,
+37,-40,50,-35,14,
+19,-7,-14,49,54,
+-5,22,-2,-29,-8,
+-27,38,13,27,48,
+12,-41,-21,-15,28,
+7,-16,-24,-19,-20,
+11,-20,9,2,13,
+23,-20,11,27,-27,
+71,-69,8,2,-6,
+22,12,16,16,9,
+-16,-8,-17,1,25,
+1,40,-37,-33,66,
+94,53,4,-22,-25,
+-41,-42,25,35,-16,
+-15,57,31,-29,-32,
+21,16,-60,45,15,
+-1,7,57,-26,-47,
+-29,11,8,15,19,
+-105,-8,54,27,10,
+-17,6,-12,-1,-10,
+4,0,23,-10,31,
+13,11,10,12,-64,
+23,-3,-8,-19,16,
+52,24,-40,16,10,
+40,5,9,0,-13,
+-7,-21,-8,-6,-7,
+-21,59,16,-53,18,
+-60,11,-47,14,-18,
+25,-13,-24,4,-39,
+16,-28,54,26,-67,
+30,27,-20,-52,20,
+-12,55,12,18,-16,
+39,-14,-6,-26,56,
+-88,-55,12,25,26,
+-37,6,75,0,-34,
+-81,54,-30,1,-7,
+49,-23,-14,21,10,
+-62,-58,-57,-47,-34,
+15,-4,34,-78,31,
+25,-11,7,50,-10,
+42,-63,14,-36,-4,
+57,55,57,53,42,
+-42,-1,15,40,37,
+15,25,-11,6,1,
+31,-2,-6,-1,-7,
+-64,34,28,30,-1,
+3,21,0,-88,-12,
+-56,25,-28,40,8,
+-28,-14,9,12,2,
+-6,-17,22,49,-6,
+-26,14,28,-20,4,
+-12,50,35,40,13,
+-38,-58,-29,17,30,
+22,60,26,-54,-39,
+-12,58,-28,-63,10,
+-21,-8,-12,26,-62,
+6,-10,-11,-22,-6,
+-7,4,1,18,2,
+-70,11,14,4,13,
+19,-24,-34,24,67,
+17,51,-21,13,23,
+54,-30,48,1,-13,
+80,26,-16,-2,13,
+-4,6,-30,29,-24,
+73,-58,30,-27,20,
+-2,-21,41,45,30,
+-27,-3,-5,-18,-20,
+-49,-3,-35,10,42,
+-19,-67,-53,-11,9,
+13,-15,-33,-51,-30,
+15,7,25,-30,4,
+28,-22,-34,54,-29,
+39,-46,20,16,34,
+-4,47,75,1,-44,
+-55,-24,7,-1,9,
+-42,50,-8,-36,41,
+68,0,-4,-10,-23,
+-15,-50,64,36,-9,
+-27,12,25,-38,-47,
+-37,32,-49,51,-36,
+2,-4,69,-26,19,
+7,45,67,46,13,
+-63,46,15,-47,4,
+-41,13,-6,5,-21,
+37,26,-55,-7,33,
+-1,-28,10,-17,-64,
+-14,0,-36,-17,93,
+-3,-9,-66,44,-21,
+3,-12,38,-6,-13,
+-12,19,13,43,-43,
+-10,-12,6,-5,9,
+-49,32,-5,2,4,
+5,15,-16,10,-21,
+8,-62,-8,64,8,
+79,-1,-66,-49,-18,
+5,40,-5,-30,-45,
+1,-6,21,-32,93,
+-18,-30,-21,32,21,
+-18,22,8,5,-41,
+-54,80,22,-10,-7,
+-8,-23,-64,66,56,
+-14,-30,-41,-46,-14,
+-29,-37,27,-14,42,
+-2,-9,-29,34,14,
+33,-14,22,4,10,
+26,26,28,32,23,
+-72,-32,3,0,-14,
+35,-42,-78,-32,6,
+29,-18,-45,-5,7,
+-33,-45,-3,-22,-34,
+8,-8,4,-51,-25,
+-9,59,-78,21,-5,
+-25,-48,66,-15,-17,
+-24,-49,-13,25,-23,
+-64,-6,40,-24,-19,
+-11,57,-33,-8,1,
+10,-52,-54,28,39,
+49,34,-11,-61,-41,
+-43,10,15,-15,51,
+30,15,-51,32,-34,
+-2,-34,14,18,16,
+1,1,-3,-3,1,
+1,-18,6,16,48,
+12,-5,-42,7,36,
+48,7,-20,-10,7,
+12,2,54,39,-38,
+37,54,4,-11,-8,
+-46,-10,5,-10,-34,
+46,-12,29,-37,39,
+36,-11,24,56,17,
+14,20,25,0,-25,
+-28,55,-7,-5,27,
+3,9,-26,-8,6,
+-24,-10,-30,-31,-34,
+18,4,22,21,40,
+-1,-29,-37,-8,-21,
+92,-29,11,-3,11,
+73,23,22,7,4,
+-44,-9,-11,21,-13,
+11,9,-78,-1,47,
+114,-12,-37,-19,-5,
+-11,-22,19,12,-30,
+7,38,45,-21,-8,
+-9,55,-45,56,-21,
+7,17,46,-57,-87,
+-6,27,31,31,7,
+-56,-12,46,21,-5,
+-12,36,3,3,-21,
+43,19,12,-7,9,
+-14,0,-9,-33,-91,
+7,26,3,-11,64,
+83,-31,-46,25,2,
+9,5,2,2,-1,
+20,-17,10,-5,-27,
+-8,20,8,-19,16,
+-21,-13,-31,5,5,
+42,24,9,34,-20,
+28,-61,22,11,-39,
+64,-20,-1,-30,-9,
+-20,24,-25,-24,-29,
+22,-60,6,-5,41,
+-9,-87,14,34,15,
+-57,52,69,15,-3,
+-102,58,16,3,6,
+60,-75,-32,26,7,
+-57,-27,-32,-24,-21,
+-29,-16,62,-46,31,
+30,-27,-15,7,15};
diff --git a/3rdparty/speex/libspeex/exc_5_64_table.c b/3rdparty/speex/libspeex/exc_5_64_table.c
new file mode 100644
index 0000000..2c66d51
--- /dev/null
+++ b/3rdparty/speex/libspeex/exc_5_64_table.c
@@ -0,0 +1,98 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: exc_5_64_table.c
+   Codebook for excitation in narrowband CELP mode (9600 bps)
+
+   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.
+*/
+
+
+const signed char exc_5_64_table[320]={
+1,5,-15,49,-66,
+-48,-4,50,-44,7,
+37,16,-18,25,-26,
+-26,-15,19,19,-27,
+-47,28,57,5,-17,
+-32,-41,68,21,-2,
+64,56,8,-16,-13,
+-26,-9,-16,11,6,
+-39,25,-19,22,-31,
+20,-45,55,-43,10,
+-16,47,-40,40,-20,
+-51,3,-17,-14,-15,
+-24,53,-20,-46,46,
+27,-68,32,3,-18,
+-5,9,-31,16,-9,
+-10,-1,-23,48,95,
+47,25,-41,-32,-3,
+15,-25,-55,36,41,
+-27,20,5,13,14,
+-22,5,2,-23,18,
+46,-15,17,-18,-34,
+-5,-8,27,-55,73,
+16,2,-1,-17,40,
+-78,33,0,2,19,
+4,53,-16,-15,-16,
+-28,-3,-13,49,8,
+-7,-29,27,-13,32,
+20,32,-61,16,14,
+41,44,40,24,20,
+7,4,48,-60,-77,
+17,-6,-48,65,-15,
+32,-30,-71,-10,-3,
+-6,10,-2,-7,-29,
+-56,67,-30,7,-5,
+86,-6,-10,0,5,
+-31,60,34,-38,-3,
+24,10,-2,30,23,
+24,-41,12,70,-43,
+15,-17,6,13,16,
+-13,8,30,-15,-8,
+5,23,-34,-98,-4,
+-13,13,-48,-31,70,
+12,31,25,24,-24,
+26,-7,33,-16,8,
+5,-11,-14,-8,-65,
+13,10,-2,-9,0,
+-3,-68,5,35,7,
+0,-31,-1,-17,-9,
+-9,16,-37,-18,-1,
+69,-48,-28,22,-21,
+-11,5,49,55,23,
+-86,-36,16,2,13,
+63,-51,30,-11,13,
+24,-18,-6,14,-19,
+1,41,9,-5,27,
+-36,-44,-34,-37,-21,
+-26,31,-39,15,43,
+5,-8,29,20,-8,
+-20,-52,-28,-1,13,
+26,-34,-10,-9,27,
+-8,8,27,-66,4,
+12,-22,49,10,-77,
+32,-18,3,-38,12,
+-3,-1,2,2,0};
diff --git a/3rdparty/speex/libspeex/exc_8_128_table.c b/3rdparty/speex/libspeex/exc_8_128_table.c
new file mode 100644
index 0000000..17ee64b
--- /dev/null
+++ b/3rdparty/speex/libspeex/exc_8_128_table.c
@@ -0,0 +1,162 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: exc_8_128_table.c
+   Codebook for excitation in narrowband CELP mode (7000 bps)
+
+   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.
+*/
+
+
+const signed char exc_8_128_table[1024] = {
+-14,9,13,-32,2,-10,31,-10,
+-8,-8,6,-4,-1,10,-64,23,
+6,20,13,6,8,-22,16,34,
+7,42,-49,-28,5,26,4,-15,
+41,34,41,32,33,24,23,14,
+8,40,34,4,-24,-41,-19,-15,
+13,-13,33,-54,24,27,-44,33,
+27,-15,-15,24,-19,14,-36,14,
+-9,24,-12,-4,37,-5,16,-34,
+5,10,33,-15,-54,-16,12,25,
+12,1,2,0,3,-1,-4,-4,
+11,2,-56,54,27,-20,13,-6,
+-46,-41,-33,-11,-5,7,12,14,
+-14,-5,8,20,6,3,4,-8,
+-5,-42,11,8,-14,25,-2,2,
+13,11,-22,39,-9,9,5,-45,
+-9,7,-9,12,-7,34,-17,-102,
+7,2,-42,18,35,-9,-34,11,
+-5,-2,3,22,46,-52,-25,-9,
+-94,8,11,-5,-5,-5,4,-7,
+-35,-7,54,5,-32,3,24,-9,
+-22,8,65,37,-1,-12,-23,-6,
+-9,-28,55,-33,14,-3,2,18,
+-60,41,-17,8,-16,17,-11,0,
+-11,29,-28,37,9,-53,33,-14,
+-9,7,-25,-7,-11,26,-32,-8,
+24,-21,22,-19,19,-10,29,-14,
+0,0,0,0,0,0,0,0,
+-5,-52,10,41,6,-30,-4,16,
+32,22,-27,-22,32,-3,-28,-3,
+3,-35,6,17,23,21,8,2,
+4,-45,-17,14,23,-4,-31,-11,
+-3,14,1,19,-11,2,61,-8,
+9,-12,7,-10,12,-3,-24,99,
+-48,23,50,-37,-5,-23,0,8,
+-14,35,-64,-5,46,-25,13,-1,
+-49,-19,-15,9,34,50,25,11,
+-6,-9,-16,-20,-32,-33,-32,-27,
+10,-8,12,-15,56,-14,-32,33,
+3,-9,1,65,-9,-9,-10,-2,
+-6,-23,9,17,3,-28,13,-32,
+4,-2,-10,4,-16,76,12,-52,
+6,13,33,-6,4,-14,-9,-3,
+1,-15,-16,28,1,-15,11,16,
+9,4,-21,-37,-40,-6,22,12,
+-15,-23,-14,-17,-16,-9,-10,-9,
+13,-39,41,5,-9,16,-38,25,
+46,-47,4,49,-14,17,-2,6,
+18,5,-6,-33,-22,44,50,-2,
+1,3,-6,7,7,-3,-21,38,
+-18,34,-14,-41,60,-13,6,16,
+-24,35,19,-13,-36,24,3,-17,
+-14,-10,36,44,-44,-29,-3,3,
+-54,-8,12,55,26,4,-2,-5,
+2,-11,22,-23,2,22,1,-25,
+-39,66,-49,21,-8,-2,10,-14,
+-60,25,6,10,27,-25,16,5,
+-2,-9,26,-13,-20,58,-2,7,
+52,-9,2,5,-4,-15,23,-1,
+-38,23,8,27,-6,0,-27,-7,
+39,-10,-14,26,11,-45,-12,9,
+-5,34,4,-35,10,43,-22,-11,
+56,-7,20,1,10,1,-26,9,
+94,11,-27,-14,-13,1,-11,0,
+14,-5,-6,-10,-4,-15,-8,-41,
+21,-5,1,-28,-8,22,-9,33,
+-23,-4,-4,-12,39,4,-7,3,
+-60,80,8,-17,2,-6,12,-5,
+1,9,15,27,31,30,27,23,
+61,47,26,10,-5,-8,-12,-13,
+5,-18,25,-15,-4,-15,-11,12,
+-2,-2,-16,-2,-6,24,12,11,
+-4,9,1,-9,14,-45,57,12,
+20,-35,26,11,-64,32,-10,-10,
+42,-4,-9,-16,32,24,7,10,
+52,-11,-57,29,0,8,0,-6,
+17,-17,-56,-40,7,20,18,12,
+-6,16,5,7,-1,9,1,10,
+29,12,16,13,-2,23,7,9,
+-3,-4,-5,18,-64,13,55,-25,
+9,-9,24,14,-25,15,-11,-40,
+-30,37,1,-19,22,-5,-31,13,
+-2,0,7,-4,16,-67,12,66,
+-36,24,-8,18,-15,-23,19,0,
+-45,-7,4,3,-13,13,35,5,
+13,33,10,27,23,0,-7,-11,
+43,-74,36,-12,2,5,-8,6,
+-33,11,-16,-14,-5,-7,-3,17,
+-34,27,-16,11,-9,15,33,-31,
+8,-16,7,-6,-7,63,-55,-17,
+11,-1,20,-46,34,-30,6,9,
+19,28,-9,5,-24,-8,-23,-2,
+31,-19,-16,-5,-15,-18,0,26,
+18,37,-5,-15,-2,17,5,-27,
+21,-33,44,12,-27,-9,17,11,
+25,-21,-31,-7,13,33,-8,-25,
+-7,7,-10,4,-6,-9,48,-82,
+-23,-8,6,11,-23,3,-3,49,
+-29,25,31,4,14,16,9,-4,
+-18,10,-26,3,5,-44,-9,9,
+-47,-55,15,9,28,1,4,-3,
+46,6,-6,-38,-29,-31,-15,-6,
+3,0,14,-6,8,-54,-50,33,
+-5,1,-14,33,-48,26,-4,-5,
+-3,-5,-3,-5,-28,-22,77,55,
+-1,2,10,10,-9,-14,-66,-49,
+11,-36,-6,-20,10,-10,16,12,
+4,-1,-16,45,-44,-50,31,-2,
+25,42,23,-32,-22,0,11,20,
+-40,-35,-40,-36,-32,-26,-21,-13,
+52,-22,6,-24,-20,17,-5,-8,
+36,-25,-11,21,-26,6,34,-8,
+7,20,-3,5,-25,-8,18,-5,
+-9,-4,1,-9,20,20,39,48,
+-24,9,5,-65,22,29,4,3,
+-43,-11,32,-6,9,19,-27,-10,
+-47,-14,24,10,-7,-36,-7,-1,
+-4,-5,-5,16,53,25,-26,-29,
+-4,-12,45,-58,-34,33,-5,2,
+-1,27,-48,31,-15,22,-5,4,
+7,7,-25,-3,11,-22,16,-12,
+8,-3,7,-11,45,14,-73,-19,
+56,-46,24,-20,28,-12,-2,-1,
+-36,-3,-33,19,-6,7,2,-15,
+5,-31,-45,8,35,13,20,0,
+-9,48,-13,-43,-3,-13,2,-5,
+72,-68,-27,2,1,-2,-7,5,
+36,33,-40,-12,-4,-5,23,19};
diff --git a/3rdparty/speex/libspeex/fftwrap.c b/3rdparty/speex/libspeex/fftwrap.c
new file mode 100644
index 0000000..35e2d05
--- /dev/null
+++ b/3rdparty/speex/libspeex/fftwrap.c
@@ -0,0 +1,287 @@
+/* Copyright (C) 2005-2006 Jean-Marc Valin 
+   File: fftwrap.c
+
+   Wrapper for various FFTs 
+
+   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
+
+/*#define USE_SMALLFT*/
+#define USE_KISS_FFT
+
+
+#include "misc.h"
+
+#define MAX_FFT_SIZE 2048
+
+#ifdef FIXED_POINT
+static int maximize_range(spx_word16_t *in, spx_word16_t *out, spx_word16_t bound, int len)
+{
+   int i, shift;
+   spx_word16_t max_val = 0;
+   for (i=0;i<len;i++)
+   {
+      if (in[i]>max_val)
+         max_val = in[i];
+      if (-in[i]>max_val)
+         max_val = -in[i];
+   }
+   shift=0;
+   while (max_val <= (bound>>1) && max_val != 0)
+   {
+      max_val <<= 1;
+      shift++;
+   }
+   for (i=0;i<len;i++)
+   {
+      out[i] = SHL16(in[i], shift);
+   }   
+   return shift;
+}
+
+static void renorm_range(spx_word16_t *in, spx_word16_t *out, int shift, int len)
+{
+   int i;
+   for (i=0;i<len;i++)
+   {
+      out[i] = PSHR16(in[i], shift);
+   }
+}
+#endif
+
+#ifdef USE_SMALLFT
+
+#include "smallft.h"
+#include <math.h>
+
+void *spx_fft_init(int size)
+{
+   struct drft_lookup *table;
+   table = speex_alloc(sizeof(struct drft_lookup));
+   spx_drft_init((struct drft_lookup *)table, size);
+   return (void*)table;
+}
+
+void spx_fft_destroy(void *table)
+{
+   spx_drft_clear(table);
+   speex_free(table);
+}
+
+void spx_fft(void *table, float *in, float *out)
+{
+   if (in==out)
+   {
+      int i;
+      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 {
+      int i;
+      float scale = 1./((struct drft_lookup *)table)->n;
+      for (i=0;i<((struct drft_lookup *)table)->n;i++)
+         out[i] = scale*in[i];
+   }
+   spx_drft_forward((struct drft_lookup *)table, out);
+}
+
+void spx_ifft(void *table, float *in, float *out)
+{
+   if (in==out)
+   {
+      speex_warning("FFT should not be done in-place");
+   } else {
+      int i;
+      for (i=0;i<((struct drft_lookup *)table)->n;i++)
+         out[i] = in[i];
+   }
+   spx_drft_backward((struct drft_lookup *)table, out);
+}
+
+#elif defined(USE_KISS_FFT)
+
+#include "kiss_fftr.h"
+#include "kiss_fft.h"
+
+struct kiss_config {
+   kiss_fftr_cfg forward;
+   kiss_fftr_cfg backward;
+   int N;
+};
+
+void *spx_fft_init(int size)
+{
+   struct kiss_config *table;
+   table = (struct kiss_config*)speex_alloc(sizeof(struct kiss_config));
+   table->forward = kiss_fftr_alloc(size,0,NULL,NULL);
+   table->backward = kiss_fftr_alloc(size,1,NULL,NULL);
+   table->N = size;
+   return table;
+}
+
+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(table);
+}
+
+#ifdef FIXED_POINT
+
+void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out)
+{
+   int shift;
+   struct kiss_config *t = (struct kiss_config *)table;
+   shift = maximize_range(in, in, 32000, t->N);
+   kiss_fftr2(t->forward, in, out);
+   renorm_range(in, in, shift, t->N);
+   renorm_range(out, out, shift, t->N);
+}
+
+#else
+
+void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out)
+{
+   int i;
+   float scale;
+   struct kiss_config *t = (struct kiss_config *)table;
+   scale = 1./t->N;
+   kiss_fftr2(t->forward, in, out);
+   for (i=0;i<t->N;i++)
+      out[i] *= scale;
+}
+#endif
+
+void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out)
+{
+   struct kiss_config *t = (struct kiss_config *)table;
+   kiss_fftri2(t->backward, in, out);
+}
+
+
+#else
+
+#error No other FFT implemented
+
+#endif
+
+
+#ifdef FIXED_POINT
+/*#include "smallft.h"*/
+
+
+void spx_fft_float(void *table, float *in, float *out)
+{
+   int i;
+#ifdef USE_SMALLFT
+   int N = ((struct drft_lookup *)table)->n;
+#elif defined(USE_KISS_FFT)
+   int N = ((struct kiss_config *)table)->N;
+#else
+#endif
+#ifdef VAR_ARRAYS
+   spx_word16_t _in[N];
+   spx_word16_t _out[N];
+#else
+   spx_word16_t _in[MAX_FFT_SIZE];
+   spx_word16_t _out[MAX_FFT_SIZE];
+#endif
+   for (i=0;i<N;i++)
+      _in[i] = (int)floor(.5+in[i]);
+   spx_fft(table, _in, _out);
+   for (i=0;i<N;i++)
+      out[i] = _out[i];
+#if 0
+   if (!fixed_point)
+   {
+      float scale;
+      struct drft_lookup t;
+      spx_drft_init(&t, ((struct kiss_config *)table)->N);
+      scale = 1./((struct kiss_config *)table)->N;
+      for (i=0;i<((struct kiss_config *)table)->N;i++)
+         out[i] = scale*in[i];
+      spx_drft_forward(&t, out);
+      spx_drft_clear(&t);
+   }
+#endif
+}
+
+void spx_ifft_float(void *table, float *in, float *out)
+{
+   int i;
+#ifdef USE_SMALLFT
+   int N = ((struct drft_lookup *)table)->n;
+#elif defined(USE_KISS_FFT)
+   int N = ((struct kiss_config *)table)->N;
+#else
+#endif
+#ifdef VAR_ARRAYS
+   spx_word16_t _in[N];
+   spx_word16_t _out[N];
+#else
+   spx_word16_t _in[MAX_FFT_SIZE];
+   spx_word16_t _out[MAX_FFT_SIZE];
+#endif
+   for (i=0;i<N;i++)
+      _in[i] = (int)floor(.5+in[i]);
+   spx_ifft(table, _in, _out);
+   for (i=0;i<N;i++)
+      out[i] = _out[i];
+#if 0
+   if (!fixed_point)
+   {
+      int i;
+      struct drft_lookup t;
+      spx_drft_init(&t, ((struct kiss_config *)table)->N);
+      for (i=0;i<((struct kiss_config *)table)->N;i++)
+         out[i] = in[i];
+      spx_drft_backward(&t, out);
+      spx_drft_clear(&t);
+   }
+#endif
+}
+
+#else
+
+void spx_fft_float(void *table, float *in, float *out)
+{
+   spx_fft(table, in, out);
+}
+void spx_ifft_float(void *table, float *in, float *out)
+{
+   spx_ifft(table, in, out);
+}
+
+#endif
diff --git a/3rdparty/speex/libspeex/fftwrap.h b/3rdparty/speex/libspeex/fftwrap.h
new file mode 100644
index 0000000..826b38e
--- /dev/null
+++ b/3rdparty/speex/libspeex/fftwrap.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 2005 Jean-Marc Valin 
+   File: fftwrap.h
+
+   Wrapper for various FFTs 
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef FFTWRAP_H
+#define FFTWRAP_H
+
+#include "misc.h"
+
+/** Compute tables for an FFT */
+void *spx_fft_init(int size);
+
+/** Destroy tables for an FFT */
+void spx_fft_destroy(void *table);
+
+/** Forward (real to half-complex) transform */
+void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out);
+
+/** Backward (half-complex to real) transform */
+void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out);
+
+/** Forward (real to half-complex) transform of float data */
+void spx_fft_float(void *table, float *in, float *out);
+
+/** Backward (half-complex to real) transform of float data */
+void spx_ifft_float(void *table, float *in, float *out);
+
+#endif
diff --git a/3rdparty/speex/libspeex/filterbank.c b/3rdparty/speex/libspeex/filterbank.c
new file mode 100644
index 0000000..187d5ee
--- /dev/null
+++ b/3rdparty/speex/libspeex/filterbank.c
@@ -0,0 +1,226 @@
+/* Copyright (C) 2006 Jean-Marc Valin */
+/**
+   @file filterbank.c
+   @brief Converting between psd and filterbank
+ */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+   1. Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+   DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "filterbank.h"
+#include "misc.h"
+#include <math.h>
+#include "math_approx.h"
+      
+#ifdef FIXED_POINT
+
+#define toBARK(n)   (MULT16_16(26829,spx_atan(SHR32(MULT16_16(97,n),2))) + MULT16_16(4588,spx_atan(MULT16_32_Q15(20,MULT16_16(n,n)))) + MULT16_16(3355,n))
+      
+#else
+#define toBARK(n)   (13.1f*atan(.00074f*(n))+2.24f*atan((n)*(n)*1.85e-8f)+1e-4f*(n))
+#endif
+       
+#define toMEL(n)    (2595.f*log10(1.f+(n)/700.f))
+
+FilterBank *filterbank_new(int banks, spx_word32_t sampling, int len, int type)
+{
+   FilterBank *bank;
+   spx_word32_t df;
+   spx_word32_t max_mel, mel_interval;
+   int i;
+   int id1;
+   int id2;
+   df = DIV32(SHL32(sampling,15),MULT16_16(2,len));
+   max_mel = toBARK(EXTRACT16(MULT16_16_Q15(QCONST16(.5f,15),sampling)));
+   mel_interval = PDIV32(max_mel,banks-1);
+   
+   bank = (FilterBank*)speex_alloc(sizeof(FilterBank));
+   bank->nb_banks = banks;
+   bank->len = len;
+   bank->bank_left = (int*)speex_alloc(len*sizeof(int));
+   bank->bank_right = (int*)speex_alloc(len*sizeof(int));
+   bank->filter_left = (spx_word16_t*)speex_alloc(len*sizeof(spx_word16_t));
+   bank->filter_right = (spx_word16_t*)speex_alloc(len*sizeof(spx_word16_t));
+   /* Think I can safely disable normalisation that for fixed-point (and probably float as well) */
+#ifndef FIXED_POINT
+   bank->scaling = (float*)speex_alloc(banks*sizeof(float));
+#endif
+   for (i=0;i<len;i++)
+   {
+      spx_word16_t curr_freq;
+      spx_word32_t mel;
+      spx_word16_t val;
+      curr_freq = EXTRACT16(MULT16_32_P15(i,df));
+      mel = toBARK(curr_freq);
+      if (mel > max_mel)
+         break;
+#ifdef FIXED_POINT
+      id1 = DIV32(mel,mel_interval);
+#else      
+      id1 = (int)(floor(mel/mel_interval));
+#endif
+      if (id1>banks-2)
+      {
+         id1 = banks-2;
+         val = Q15_ONE;
+      } else {
+         val = DIV32_16(mel - id1*mel_interval,EXTRACT16(PSHR32(mel_interval,15)));
+      }
+      id2 = id1+1;
+      bank->bank_left[i] = id1;
+      bank->filter_left[i] = SUB16(Q15_ONE,val);
+      bank->bank_right[i] = id2;
+      bank->filter_right[i] = val;
+   }
+   
+   /* Think I can safely disable normalisation for fixed-point (and probably float as well) */
+#ifndef FIXED_POINT
+   for (i=0;i<bank->nb_banks;i++)
+      bank->scaling[i] = 0;
+   for (i=0;i<bank->len;i++)
+   {
+      int id = bank->bank_left[i];
+      bank->scaling[id] += bank->filter_left[i];
+      id = bank->bank_right[i];
+      bank->scaling[id] += bank->filter_right[i];
+   }
+   for (i=0;i<bank->nb_banks;i++)
+      bank->scaling[i] = Q15_ONE/(bank->scaling[i]);
+#endif
+   return bank;
+}
+
+void filterbank_destroy(FilterBank *bank)
+{
+   speex_free(bank->bank_left);
+   speex_free(bank->bank_right);
+   speex_free(bank->filter_left);
+   speex_free(bank->filter_right);
+#ifndef FIXED_POINT
+   speex_free(bank->scaling);
+#endif
+   speex_free(bank);
+}
+
+void filterbank_compute_bank32(FilterBank *bank, spx_word32_t *ps, spx_word32_t *mel)
+{
+   int i;
+   for (i=0;i<bank->nb_banks;i++)
+      mel[i] = 0;
+
+   for (i=0;i<bank->len;i++)
+   {
+      int id;
+      id = bank->bank_left[i];
+      mel[id] += MULT16_32_P15(bank->filter_left[i],ps[i]);
+      id = bank->bank_right[i];
+      mel[id] += MULT16_32_P15(bank->filter_right[i],ps[i]);
+   }
+   /* Think I can safely disable normalisation that for fixed-point (and probably float as well) */
+#ifndef FIXED_POINT
+   /*for (i=0;i<bank->nb_banks;i++)
+      mel[i] = MULT16_32_P15(Q15(bank->scaling[i]),mel[i]);
+   */
+#endif
+}
+
+void filterbank_compute_psd16(FilterBank *bank, spx_word16_t *mel, spx_word16_t *ps)
+{
+   int i;
+   for (i=0;i<bank->len;i++)
+   {
+      spx_word32_t tmp;
+      int id1, id2;
+      id1 = bank->bank_left[i];
+      id2 = bank->bank_right[i];
+      tmp = MULT16_16(mel[id1],bank->filter_left[i]);
+      tmp += MULT16_16(mel[id2],bank->filter_right[i]);
+      ps[i] = EXTRACT16(PSHR32(tmp,15));
+   }
+}
+
+
+#ifndef FIXED_POINT
+void filterbank_compute_bank(FilterBank *bank, float *ps, float *mel)
+{
+   int i;
+   for (i=0;i<bank->nb_banks;i++)
+      mel[i] = 0;
+
+   for (i=0;i<bank->len;i++)
+   {
+      int id = bank->bank_left[i];
+      mel[id] += bank->filter_left[i]*ps[i];
+      id = bank->bank_right[i];
+      mel[id] += bank->filter_right[i]*ps[i];
+   }
+   for (i=0;i<bank->nb_banks;i++)
+      mel[i] *= bank->scaling[i];
+}
+
+void filterbank_compute_psd(FilterBank *bank, float *mel, float *ps)
+{
+   int i;
+   for (i=0;i<bank->len;i++)
+   {
+      int id = bank->bank_left[i];
+      ps[i] = mel[id]*bank->filter_left[i];
+      id = bank->bank_right[i];
+      ps[i] += mel[id]*bank->filter_right[i];
+   }
+}
+
+void filterbank_psy_smooth(FilterBank *bank, float *ps, float *mask)
+{
+   /* Low freq slope: 14 dB/Bark*/
+   /* High freq slope: 9 dB/Bark*/
+   /* Noise vs tone: 5 dB difference */
+   /* FIXME: Temporary kludge */
+   float bark[100];
+   int i;
+   /* Assumes 1/3 Bark resolution */
+   float decay_low = 0.34145f;
+   float decay_high = 0.50119f;
+   filterbank_compute_bank(bank, ps, bark);
+   for (i=1;i<bank->nb_banks;i++)
+   {
+      /*float decay_high = 13-1.6*log10(bark[i-1]);
+      decay_high = pow(10,(-decay_high/30.f));*/
+      bark[i] = bark[i] + decay_high*bark[i-1];
+   }
+   for (i=bank->nb_banks-2;i>=0;i--)
+   {
+      bark[i] = bark[i] + decay_low*bark[i+1];
+   }
+   filterbank_compute_psd(bank, bark, mask);
+}
+
+#endif
diff --git a/3rdparty/speex/libspeex/filterbank.h b/3rdparty/speex/libspeex/filterbank.h
new file mode 100644
index 0000000..5ded6b9
--- /dev/null
+++ b/3rdparty/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 "misc.h"
+
+typedef struct {
+   int *bank_left;
+   int *bank_right;
+   spx_word16_t *filter_left;
+   spx_word16_t *filter_right;
+#ifndef FIXED_POINT
+   float *scaling;
+#endif
+   int nb_banks;
+   int len;
+} FilterBank;
+
+
+FilterBank *filterbank_new(int banks, spx_word32_t sampling, int len, int type);
+
+void filterbank_destroy(FilterBank *bank);
+
+void filterbank_compute_bank32(FilterBank *bank, spx_word32_t *ps, spx_word32_t *mel);
+
+void filterbank_compute_psd16(FilterBank *bank, spx_word16_t *mel, spx_word16_t *psd);
+
+#ifndef FIXED_POINT
+void filterbank_compute_bank(FilterBank *bank, float *psd, float *mel);
+void filterbank_compute_psd(FilterBank *bank, float *mel, float *psd);
+#endif
+
+
+#endif
diff --git a/3rdparty/speex/libspeex/filters.c b/3rdparty/speex/libspeex/filters.c
new file mode 100644
index 0000000..48b4753
--- /dev/null
+++ b/3rdparty/speex/libspeex/filters.c
@@ -0,0 +1,821 @@
+/* Copyright (C) 2002-2006 Jean-Marc Valin 
+   File: filters.c
+   Various analysis/synthesis filters
+
+   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 "filters.h"
+#include "stack_alloc.h"
+#include "misc.h"
+#include "math_approx.h"
+#include "ltp.h"
+#include <math.h>
+
+#ifdef _USE_SSE
+#include "filters_sse.h"
+#elif defined (ARM4_ASM) || defined(ARM5E_ASM)
+#include "filters_arm4.h"
+#elif defined (BFIN_ASM)
+#include "filters_bfin.h"
+#endif
+
+
+
+void bw_lpc(spx_word16_t gamma, const spx_coef_t *lpc_in, spx_coef_t *lpc_out, int order)
+{
+   int i;
+   spx_word16_t tmp=gamma;
+   for (i=0;i<order;i++)
+   {
+      lpc_out[i] = MULT16_16_P15(tmp,lpc_in[i]);
+      tmp = MULT16_16_P15(tmp, gamma);
+   }
+}
+
+void sanitize_values32(spx_word32_t *vec, spx_word32_t min_val, spx_word32_t max_val, int len)
+{
+   int i;
+   for (i=0;i<len;i++)
+   {
+      /* It's important we do the test that way so we can catch NaNs, which are neither greater nor smaller */
+      if (!(vec[i]>=min_val && vec[i] <= max_val))
+      {
+         if (vec[i] < min_val)
+            vec[i] = min_val;
+         else if (vec[i] > max_val)
+            vec[i] = max_val;
+         else /* Has to be NaN */
+            vec[i] = 0;
+      }
+   }
+}
+
+void highpass(const spx_word16_t *x, spx_word16_t *y, int len, int filtID, spx_mem_t *mem)
+{
+   int i;
+#ifdef FIXED_POINT
+   const spx_word16_t Pcoef[5][3] = {{16384, -31313, 14991}, {16384, -31569, 15249}, {16384, -31677, 15328}, {16384, -32313, 15947}, {16384, -22446, 6537}};
+   const spx_word16_t Zcoef[5][3] = {{15672, -31344, 15672}, {15802, -31601, 15802}, {15847, -31694, 15847}, {16162, -32322, 16162}, {14418, -28836, 14418}};
+#else
+   const spx_word16_t Pcoef[5][3] = {{1.00000f, -1.91120f, 0.91498f}, {1.00000f, -1.92683f, 0.93071f}, {1.00000f, -1.93338f, 0.93553f}, {1.00000f, -1.97226f, 0.97332f}, {1.00000f, -1.37000f, 0.39900f}};
+   const spx_word16_t Zcoef[5][3] = {{0.95654f, -1.91309f, 0.95654f}, {0.96446f, -1.92879f, 0.96446f}, {0.96723f, -1.93445f, 0.96723f}, {0.98645f, -1.97277f, 0.98645f}, {0.88000f, -1.76000f, 0.88000f}};
+#endif
+   const spx_word16_t *den, *num;
+   if (filtID>4)
+      filtID=4;
+   
+   den = Pcoef[filtID]; num = Zcoef[filtID];
+   /*return;*/
+   for (i=0;i<len;i++)
+   {
+      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]), 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;
+   }
+}
+
+#ifdef FIXED_POINT
+
+/* FIXME: These functions are ugly and probably introduce too much error */
+void signal_mul(const spx_sig_t *x, spx_sig_t *y, spx_word32_t scale, int len)
+{
+   int i;
+   for (i=0;i<len;i++)
+   {
+      y[i] = SHL32(MULT16_32_Q14(EXTRACT16(SHR32(x[i],7)),scale),7);
+   }
+}
+
+void signal_div(const spx_word16_t *x, spx_word16_t *y, spx_word32_t scale, int len)
+{
+   int i;
+   if (scale > SHL32(EXTEND32(SIG_SCALING), 8))
+   {
+      spx_word16_t scale_1;
+      scale = PSHR32(scale, SIG_SHIFT);
+      scale_1 = EXTRACT16(PDIV32_16(SHL32(EXTEND32(SIG_SCALING),7),scale));
+      for (i=0;i<len;i++)
+      {
+         y[i] = MULT16_16_P15(scale_1, x[i]);
+      }
+   } else if (scale > SHR32(EXTEND32(SIG_SCALING), 2)) {
+      spx_word16_t scale_1;
+      scale = PSHR32(scale, SIG_SHIFT-5);
+      scale_1 = DIV32_16(SHL32(EXTEND32(SIG_SCALING),3),scale);
+      for (i=0;i<len;i++)
+      {
+         y[i] = PSHR32(MULT16_16(scale_1, SHL16(x[i],2)),8);
+      }
+   } else {
+      spx_word16_t scale_1;
+      scale = PSHR32(scale, SIG_SHIFT-7);
+      if (scale < 5)
+         scale = 5;
+      scale_1 = DIV32_16(SHL32(EXTEND32(SIG_SCALING),3),scale);
+      for (i=0;i<len;i++)
+      {
+         y[i] = PSHR32(MULT16_16(scale_1, SHL16(x[i],2)),6);
+      }
+   }
+}
+
+#else
+
+void signal_mul(const spx_sig_t *x, spx_sig_t *y, spx_word32_t scale, int len)
+{
+   int i;
+   for (i=0;i<len;i++)
+      y[i] = scale*x[i];
+}
+
+void signal_div(const spx_sig_t *x, spx_sig_t *y, spx_word32_t scale, int len)
+{
+   int i;
+   float scale_1 = 1/scale;
+   for (i=0;i<len;i++)
+      y[i] = scale_1*x[i];
+}
+#endif
+
+
+
+#ifdef FIXED_POINT
+
+
+
+spx_word16_t compute_rms(const spx_sig_t *x, int len)
+{
+   int i;
+   spx_word32_t sum=0;
+   spx_sig_t max_val=1;
+   int sig_shift;
+
+   for (i=0;i<len;i++)
+   {
+      spx_sig_t tmp = x[i];
+      if (tmp<0)
+         tmp = -tmp;
+      if (tmp > max_val)
+         max_val = tmp;
+   }
+
+   sig_shift=0;
+   while (max_val>16383)
+   {
+      sig_shift++;
+      max_val >>= 1;
+   }
+
+   for (i=0;i<len;i+=4)
+   {
+      spx_word32_t sum2=0;
+      spx_word16_t tmp;
+      tmp = EXTRACT16(SHR32(x[i],sig_shift));
+      sum2 = MAC16_16(sum2,tmp,tmp);
+      tmp = EXTRACT16(SHR32(x[i+1],sig_shift));
+      sum2 = MAC16_16(sum2,tmp,tmp);
+      tmp = EXTRACT16(SHR32(x[i+2],sig_shift));
+      sum2 = MAC16_16(sum2,tmp,tmp);
+      tmp = EXTRACT16(SHR32(x[i+3],sig_shift));
+      sum2 = MAC16_16(sum2,tmp,tmp);
+      sum = ADD32(sum,SHR32(sum2,6));
+   }
+   
+   return EXTRACT16(PSHR32(SHL32(EXTEND32(spx_sqrt(DIV32(sum,len))),(sig_shift+3)),SIG_SHIFT));
+}
+
+spx_word16_t compute_rms16(const spx_word16_t *x, int len)
+{
+   int i;
+   spx_word16_t max_val=10; 
+
+   for (i=0;i<len;i++)
+   {
+      spx_sig_t tmp = x[i];
+      if (tmp<0)
+         tmp = -tmp;
+      if (tmp > max_val)
+         max_val = tmp;
+   }
+   if (max_val>16383)
+   {
+      spx_word32_t sum=0;
+      for (i=0;i<len;i+=4)
+      {
+         spx_word32_t sum2=0;
+         sum2 = MAC16_16(sum2,SHR16(x[i],1),SHR16(x[i],1));
+         sum2 = MAC16_16(sum2,SHR16(x[i+1],1),SHR16(x[i+1],1));
+         sum2 = MAC16_16(sum2,SHR16(x[i+2],1),SHR16(x[i+2],1));
+         sum2 = MAC16_16(sum2,SHR16(x[i+3],1),SHR16(x[i+3],1));
+         sum = ADD32(sum,SHR32(sum2,6));
+      }
+      return SHL16(spx_sqrt(DIV32(sum,len)),4);
+   } else {
+      spx_word32_t sum=0;
+      int sig_shift=0;
+      if (max_val < 8192)
+         sig_shift=1;
+      if (max_val < 4096)
+         sig_shift=2;
+      if (max_val < 2048)
+         sig_shift=3;
+      for (i=0;i<len;i+=4)
+      {
+         spx_word32_t sum2=0;
+         sum2 = MAC16_16(sum2,SHL16(x[i],sig_shift),SHL16(x[i],sig_shift));
+         sum2 = MAC16_16(sum2,SHL16(x[i+1],sig_shift),SHL16(x[i+1],sig_shift));
+         sum2 = MAC16_16(sum2,SHL16(x[i+2],sig_shift),SHL16(x[i+2],sig_shift));
+         sum2 = MAC16_16(sum2,SHL16(x[i+3],sig_shift),SHL16(x[i+3],sig_shift));
+         sum = ADD32(sum,SHR32(sum2,6));
+      }
+      return SHL16(spx_sqrt(DIV32(sum,len)),3-sig_shift);   
+   }
+}
+
+#ifndef OVERRIDE_NORMALIZE16
+int normalize16(const spx_sig_t *x, spx_word16_t *y, spx_sig_t max_scale, int len)
+{
+   int i;
+   spx_sig_t max_val=1;
+   int sig_shift;
+   
+   for (i=0;i<len;i++)
+   {
+      spx_sig_t tmp = x[i];
+      if (tmp<0)
+         tmp = NEG32(tmp);
+      if (tmp >= max_val)
+         max_val = tmp;
+   }
+
+   sig_shift=0;
+   while (max_val>max_scale)
+   {
+      sig_shift++;
+      max_val >>= 1;
+   }
+
+   for (i=0;i<len;i++)
+      y[i] = EXTRACT16(SHR32(x[i], sig_shift));
+   
+   return sig_shift;
+}
+#endif
+
+#else
+
+spx_word16_t compute_rms(const spx_sig_t *x, int len)
+{
+   int i;
+   float sum=0;
+   for (i=0;i<len;i++)
+   {
+      sum += x[i]*x[i];
+   }
+   return sqrt(.1+sum/len);
+}
+spx_word16_t compute_rms16(const spx_word16_t *x, int len)
+{
+   return compute_rms(x, len);
+}
+#endif
+
+
+
+#ifndef OVERRIDE_FILTER_MEM16
+void filter_mem16(const spx_word16_t *x, const spx_coef_t *num, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack)
+{
+   int i,j;
+   spx_word16_t xi,yi,nyi;
+   for (i=0;i<N;i++)
+   {
+      xi= x[i];
+      yi = EXTRACT16(SATURATE(ADD32(EXTEND32(x[i]),PSHR32(mem[0],LPC_SHIFT)),32767));
+      nyi = NEG16(yi);
+      for (j=0;j<ord-1;j++)
+      {
+         mem[j] = MAC16_16(MAC16_16(mem[j+1], num[j],xi), den[j],nyi);
+      }
+      mem[ord-1] = ADD32(MULT16_16(num[ord-1],xi), MULT16_16(den[ord-1],nyi));
+      y[i] = yi;
+   }
+}
+#endif
+
+#ifndef OVERRIDE_IIR_MEM16
+void iir_mem16(const spx_word16_t *x, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack)
+{
+   int i,j;
+   spx_word16_t yi,nyi;
+
+   for (i=0;i<N;i++)
+   {
+      yi = EXTRACT16(SATURATE(ADD32(EXTEND32(x[i]),PSHR32(mem[0],LPC_SHIFT)),32767));
+      nyi = NEG16(yi);
+      for (j=0;j<ord-1;j++)
+      {
+         mem[j] = MAC16_16(mem[j+1],den[j],nyi);
+      }
+      mem[ord-1] = MULT16_16(den[ord-1],nyi);
+      y[i] = yi;
+   }
+}
+#endif
+
+#ifndef OVERRIDE_FIR_MEM16
+void fir_mem16(const spx_word16_t *x, const spx_coef_t *num, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack)
+{
+   int i,j;
+   spx_word16_t xi,yi;
+
+   for (i=0;i<N;i++)
+   {
+      xi=x[i];
+      yi = EXTRACT16(SATURATE(ADD32(EXTEND32(x[i]),PSHR32(mem[0],LPC_SHIFT)),32767));
+      for (j=0;j<ord-1;j++)
+      {
+         mem[j] = MAC16_16(mem[j+1], num[j],xi);
+      }
+      mem[ord-1] = MULT16_16(num[ord-1],xi);
+      y[i] = yi;
+   }
+}
+#endif
+
+
+void syn_percep_zero16(const spx_word16_t *xx, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack)
+{
+   int i;
+   VARDECL(spx_mem_t *mem);
+   ALLOC(mem, ord, spx_mem_t);
+   for (i=0;i<ord;i++)
+      mem[i]=0;
+   iir_mem16(xx, ak, y, N, ord, mem, stack);
+   for (i=0;i<ord;i++)
+      mem[i]=0;
+   filter_mem16(y, awk1, awk2, y, N, ord, mem, stack);
+}
+void residue_percep_zero16(const spx_word16_t *xx, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack)
+{
+   int i;
+   VARDECL(spx_mem_t *mem);
+   ALLOC(mem, ord, spx_mem_t);
+   for (i=0;i<ord;i++)
+      mem[i]=0;
+   filter_mem16(xx, ak, awk1, y, N, ord, mem, stack);
+   for (i=0;i<ord;i++)
+      mem[i]=0;
+   fir_mem16(y, awk2, y, N, ord, mem, stack);
+}
+
+
+#ifndef OVERRIDE_COMPUTE_IMPULSE_RESPONSE
+void compute_impulse_response(const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack)
+{
+   int i,j;
+   spx_word16_t y1, ny1i, ny2i;
+   VARDECL(spx_mem_t *mem1);
+   VARDECL(spx_mem_t *mem2);
+   ALLOC(mem1, ord, spx_mem_t);
+   ALLOC(mem2, ord, spx_mem_t);
+   
+   y[0] = LPC_SCALING;
+   for (i=0;i<ord;i++)
+      y[i+1] = awk1[i];
+   i++;
+   for (;i<N;i++)
+      y[i] = VERY_SMALL;
+   for (i=0;i<ord;i++)
+      mem1[i] = mem2[i] = 0;
+   for (i=0;i<N;i++)
+   {
+      y1 = ADD16(y[i], EXTRACT16(PSHR32(mem1[0],LPC_SHIFT)));
+      ny1i = NEG16(y1);
+      y[i] = PSHR32(ADD32(SHL32(EXTEND32(y1),LPC_SHIFT+1),mem2[0]),LPC_SHIFT);
+      ny2i = NEG16(y[i]);
+      for (j=0;j<ord-1;j++)
+      {
+         mem1[j] = MAC16_16(mem1[j+1], awk2[j],ny1i);
+         mem2[j] = MAC16_16(mem2[j+1], ak[j],ny2i);
+      }
+      mem1[ord-1] = MULT16_16(awk2[ord-1],ny1i);
+      mem2[ord-1] = MULT16_16(ak[ord-1],ny2i);
+   }
+}
+#endif
+
+/* Decomposes a signal into low-band and high-band using a QMF */
+void qmf_decomp(const spx_word16_t *xx, const spx_word16_t *aa, spx_word16_t *y1, spx_word16_t *y2, int N, int M, spx_word16_t *mem, char *stack)
+{
+   int i,j,k,M2;
+   VARDECL(spx_word16_t *a);
+   VARDECL(spx_word16_t *x);
+   spx_word16_t *x2;
+   
+   ALLOC(a, M, spx_word16_t);
+   ALLOC(x, N+M-1, spx_word16_t);
+   x2=x+M-1;
+   M2=M>>1;
+   for (i=0;i<M;i++)
+      a[M-i-1]= aa[i];
+   for (i=0;i<M-1;i++)
+      x[i]=mem[M-i-2];
+   for (i=0;i<N;i++)
+      x[i+M-1]=SHR16(xx[i],1);
+   for (i=0;i<M-1;i++)
+      mem[i]=SHR16(xx[N-i-1],1);
+   for (i=0,k=0;i<N;i+=2,k++)
+   {
+      spx_word32_t y1k=0, y2k=0;
+      for (j=0;j<M2;j++)
+      {
+         y1k=ADD32(y1k,MULT16_16(a[j],ADD16(x[i+j],x2[i-j])));
+         y2k=SUB32(y2k,MULT16_16(a[j],SUB16(x[i+j],x2[i-j])));
+         j++;
+         y1k=ADD32(y1k,MULT16_16(a[j],ADD16(x[i+j],x2[i-j])));
+         y2k=ADD32(y2k,MULT16_16(a[j],SUB16(x[i+j],x2[i-j])));
+      }
+      y1[k] = EXTRACT16(SATURATE(PSHR32(y1k,15),32767));
+      y2[k] = EXTRACT16(SATURATE(PSHR32(y2k,15),32767));
+   }
+}
+
+/* Re-synthesised a signal from the QMF low-band and high-band signals */
+void qmf_synth(const spx_word16_t *x1, const spx_word16_t *x2, const spx_word16_t *a, spx_word16_t *y, int N, int M, spx_word32_t *mem1, spx_word32_t *mem2, char *stack)
+   /* assumptions:
+      all odd x[i] are zero -- well, actually they are left out of the array now
+      N and M are multiples of 4 */
+{
+   int i, j;
+   int M2, N2;
+   VARDECL(spx_word16_t *xx1);
+   VARDECL(spx_word16_t *xx2);
+   
+   M2 = M>>1;
+   N2 = N>>1;
+   ALLOC(xx1, M2+N2, spx_word16_t);
+   ALLOC(xx2, M2+N2, spx_word16_t);
+
+   for (i = 0; i < N2; i++)
+      xx1[i] = x1[N2-1-i];
+   for (i = 0; i < M2; i++)
+      xx1[N2+i] = mem1[2*i+1];
+   for (i = 0; i < N2; i++)
+      xx2[i] = x2[N2-1-i];
+   for (i = 0; i < M2; i++)
+      xx2[N2+i] = mem2[2*i+1];
+
+   for (i = 0; i < N2; i += 2) {
+      spx_sig_t y0, y1, y2, y3;
+      spx_word16_t x10, x20;
+
+      y0 = y1 = y2 = y3 = 0;
+      x10 = xx1[N2-2-i];
+      x20 = xx2[N2-2-i];
+
+      for (j = 0; j < M2; j += 2) {
+         spx_word16_t x11, x21;
+         spx_word16_t a0, a1;
+
+         a0 = a[2*j];
+         a1 = a[2*j+1];
+         x11 = xx1[N2-1+j-i];
+         x21 = xx2[N2-1+j-i];
+
+#ifdef FIXED_POINT
+         /* We multiply twice by the same coef to avoid overflows */
+         y0 = MAC16_16(MAC16_16(y0, a0, x11), NEG16(a0), x21);
+         y1 = MAC16_16(MAC16_16(y1, a1, x11), a1, x21);
+         y2 = MAC16_16(MAC16_16(y2, a0, x10), NEG16(a0), x20);
+         y3 = MAC16_16(MAC16_16(y3, a1, x10), a1, x20);
+#else
+         y0 = ADD32(y0,MULT16_16(a0, x11-x21));
+         y1 = ADD32(y1,MULT16_16(a1, x11+x21));
+         y2 = ADD32(y2,MULT16_16(a0, x10-x20));
+         y3 = ADD32(y3,MULT16_16(a1, x10+x20));
+#endif
+         a0 = a[2*j+2];
+         a1 = a[2*j+3];
+         x10 = xx1[N2+j-i];
+         x20 = xx2[N2+j-i];
+
+#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
+      }
+#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 < 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
+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
+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
+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
+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
+
+int interp_pitch(
+spx_word16_t *exc,          /*decoded excitation*/
+spx_word16_t *interp,          /*decoded excitation*/
+int pitch,               /*pitch period*/
+int len
+)
+{
+   int i,j,k;
+   spx_word32_t corr[4][7];
+   spx_word32_t maxcorr;
+   int maxi, maxj;
+   for (i=0;i<7;i++)
+   {
+      corr[0][i] = inner_prod(exc, exc-pitch-3+i, len);
+   }
+   for (i=0;i<3;i++)
+   {
+      for (j=0;j<7;j++)
+      {
+         int i1, i2;
+         spx_word32_t tmp=0;
+         i1 = 3-j;
+         if (i1<0)
+            i1 = 0;
+         i2 = 10-j;
+         if (i2>7)
+            i2 = 7;
+         for (k=i1;k<i2;k++)
+            tmp += MULT16_32_Q15(shift_filt[i][k],corr[0][j+k-3]);
+         corr[i+1][j] = tmp;
+      }
+   }
+   maxi=maxj=0;
+   maxcorr = corr[0][0];
+   for (i=0;i<4;i++)
+   {
+      for (j=0;j<7;j++)
+      {
+         if (corr[i][j] > maxcorr)
+         {
+            maxcorr = corr[i][j];
+            maxi=i;
+            maxj=j;
+         }
+      }
+   }
+   for (i=0;i<len;i++)
+   {
+      spx_word32_t tmp = 0;
+      if (maxi>0)
+      {
+         for (k=0;k<7;k++)
+         {
+            tmp += MULT16_16(exc[i-(pitch-maxj+3)+k-3],shift_filt[maxi-1][k]);
+         }
+      } else {
+         tmp = SHL32(exc[i-(pitch-maxj+3)],15);
+      }
+      interp[i] = PSHR32(tmp,15);
+   }
+   return pitch-maxj+3;
+}
+
+void multicomb(
+spx_word16_t *exc,          /*decoded excitation*/
+spx_word16_t *new_exc,      /*enhanced excitation*/
+spx_coef_t *ak,           /*LPC filter coefs*/
+int p,               /*LPC order*/
+int nsf,             /*sub-frame size*/
+int pitch,           /*pitch period*/
+int max_pitch,
+spx_word16_t  comb_gain,    /*gain of comb filter*/
+char *stack
+)
+{
+   int i; 
+   VARDECL(spx_word16_t *iexc);
+   spx_word16_t old_ener, new_ener;
+   int corr_pitch;
+   
+   spx_word16_t iexc0_mag, iexc1_mag, exc_mag;
+   spx_word32_t corr0, corr1;
+   spx_word16_t gain0, gain1;
+   spx_word16_t pgain1, pgain2;
+   spx_word16_t c1, c2;
+   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];
+   spx_word16_t ol_pitch_coef;
+   open_loop_nbest_pitch(exc, 20, 120, nsf, 
+                         nol_pitch, nol_pitch_coef, 6, stack);
+   corr_pitch=nol_pitch[0];
+   ol_pitch_coef = nol_pitch_coef[0];
+   /*Try to remove pitch multiples*/
+   for (i=1;i<6;i++)
+   {
+#ifdef FIXED_POINT
+      if ((nol_pitch_coef[i]>MULT16_16_Q15(nol_pitch_coef[0],19661)) && 
+#else
+      if ((nol_pitch_coef[i]>.6*nol_pitch_coef[0]) && 
+#endif
+         (ABS(2*nol_pitch[i]-corr_pitch)<=2 || ABS(3*nol_pitch[i]-corr_pitch)<=3 || 
+         ABS(4*nol_pitch[i]-corr_pitch)<=4 || ABS(5*nol_pitch[i]-corr_pitch)<=5))
+      {
+         corr_pitch = nol_pitch[i];
+      }
+   }
+#else
+   corr_pitch = pitch;
+#endif
+   
+   ALLOC(iexc, 2*nsf, spx_word16_t);
+   
+   interp_pitch(exc, iexc, corr_pitch, 80);
+   if (corr_pitch>max_pitch)
+      interp_pitch(exc, iexc+nsf, 2*corr_pitch, 80);
+   else
+      interp_pitch(exc, iexc+nsf, -corr_pitch, 80);
+
+#ifdef FIXED_POINT
+   for (i=0;i<nsf;i++)
+   {
+      if (ABS16(exc[i])>16383)
+      {
+         scaledown = 1;
+         break;
+      }
+   }
+   if (scaledown)
+   {
+      for (i=0;i<nsf;i++)
+         exc[i] = SHR16(exc[i],1);
+      for (i=0;i<2*nsf;i++)
+         iexc[i] = SHR16(iexc[i],1);
+   }
+#endif
+   /*interp_pitch(exc, iexc+2*nsf, 2*corr_pitch, 80);*/
+   
+   /*printf ("%d %d %f\n", pitch, corr_pitch, max_corr*ener_1);*/
+   iexc0_mag = spx_sqrt(1000+inner_prod(iexc,iexc,nsf));
+   iexc1_mag = spx_sqrt(1000+inner_prod(iexc+nsf,iexc+nsf,nsf));
+   exc_mag = spx_sqrt(1+inner_prod(exc,exc,nsf));
+   corr0  = inner_prod(iexc,exc,nsf);
+   if (corr0<0)
+      corr0=0;
+   corr1 = inner_prod(iexc+nsf,exc,nsf);
+   if (corr1<0)
+      corr1=0;
+#ifdef FIXED_POINT
+   /* Doesn't cost much to limit the ratio and it makes the rest easier */
+   if (SHL32(EXTEND32(iexc0_mag),6) < EXTEND32(exc_mag))
+      iexc0_mag = ADD16(1,PSHR16(exc_mag,6));
+   if (SHL32(EXTEND32(iexc1_mag),6) < EXTEND32(exc_mag))
+      iexc1_mag = ADD16(1,PSHR16(exc_mag,6));
+#endif
+   if (corr0 > MULT16_16(iexc0_mag,exc_mag))
+      pgain1 = QCONST16(1., 14);
+   else
+      pgain1 = PDIV32_16(SHL32(PDIV32(corr0, exc_mag),14),iexc0_mag);
+   if (corr1 > MULT16_16(iexc1_mag,exc_mag))
+      pgain2 = QCONST16(1., 14);
+   else
+      pgain2 = PDIV32_16(SHL32(PDIV32(corr1, exc_mag),14),iexc1_mag);
+   gg1 = PDIV32_16(SHL32(EXTEND32(exc_mag),8), iexc0_mag);
+   gg2 = PDIV32_16(SHL32(EXTEND32(exc_mag),8), iexc1_mag);
+   if (comb_gain>0)
+   {
+#ifdef FIXED_POINT
+      c1 = (MULT16_16_Q15(QCONST16(.4,15),comb_gain)+QCONST16(.07,15));
+      c2 = QCONST16(.5,15)+MULT16_16_Q14(QCONST16(1.72,14),(c1-QCONST16(.07,15)));
+#else
+      c1 = .4*comb_gain+.07;
+      c2 = .5+1.72*(c1-.07);
+#endif
+   } else 
+   {
+      c1=c2=0;
+   }
+#ifdef FIXED_POINT
+   g1 = 32767 - MULT16_16_Q13(MULT16_16_Q15(c2, pgain1),pgain1);
+   g2 = 32767 - MULT16_16_Q13(MULT16_16_Q15(c2, pgain2),pgain2);
+#else
+   g1 = 1-c2*pgain1*pgain1;
+   g2 = 1-c2*pgain2*pgain2;
+#endif
+   if (g1<c1)
+      g1 = c1;
+   if (g2<c1)
+      g2 = c1;
+   g1 = (spx_word16_t)PDIV32_16(SHL32(EXTEND32(c1),14),(spx_word16_t)g1);
+   g2 = (spx_word16_t)PDIV32_16(SHL32(EXTEND32(c1),14),(spx_word16_t)g2);
+   if (corr_pitch>max_pitch)
+   {
+      gain0 = MULT16_16_Q15(QCONST16(.7,15),MULT16_16_Q14(g1,gg1));
+      gain1 = MULT16_16_Q15(QCONST16(.3,15),MULT16_16_Q14(g2,gg2));
+   } else {
+      gain0 = MULT16_16_Q15(QCONST16(.6,15),MULT16_16_Q14(g1,gg1));
+      gain1 = MULT16_16_Q15(QCONST16(.6,15),MULT16_16_Q14(g2,gg2));
+   }
+   for (i=0;i<nsf;i++)
+      new_exc[i] = ADD16(exc[i], EXTRACT16(PSHR32(ADD32(MULT16_16(gain0,iexc[i]), MULT16_16(gain1,iexc[i+nsf])),8)));
+   /* FIXME: compute_rms16 is currently not quite accurate enough (but close) */
+   new_ener = compute_rms16(new_exc, nsf);
+   old_ener = compute_rms16(exc, nsf);
+   
+   if (old_ener < 1)
+      old_ener = 1;
+   if (new_ener < 1)
+      new_ener = 1;
+   if (old_ener > new_ener)
+      old_ener = new_ener;
+   ngain = PDIV32_16(SHL32(EXTEND32(old_ener),14),new_ener);
+   
+   for (i=0;i<nsf;i++)
+      new_exc[i] = MULT16_16_Q14(ngain, new_exc[i]);
+#ifdef FIXED_POINT
+   if (scaledown)
+   {
+      for (i=0;i<nsf;i++)
+         exc[i] = SHL16(exc[i],1);
+      for (i=0;i<nsf;i++)
+         new_exc[i] = SHL16(SATURATE16(new_exc[i],16383),1);
+   }
+#endif
+}
+
diff --git a/3rdparty/speex/libspeex/filters.h b/3rdparty/speex/libspeex/filters.h
new file mode 100644
index 0000000..b363a9a
--- /dev/null
+++ b/3rdparty/speex/libspeex/filters.h
@@ -0,0 +1,90 @@
+/* Copyright (C) 2002 Jean-Marc Valin */
+/**
+   @file filters.h
+   @brief Various analysis/synthesis filters
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FILTERS_H
+#define FILTERS_H
+
+#include "misc.h"
+
+spx_word16_t compute_rms(const spx_sig_t *x, int len);
+spx_word16_t compute_rms16(const spx_word16_t *x, int len);
+void signal_mul(const spx_sig_t *x, spx_sig_t *y, spx_word32_t scale, int len);
+void signal_div(const spx_word16_t *x, spx_word16_t *y, spx_word32_t scale, int len);
+
+#ifdef FIXED_POINT
+
+int normalize16(const spx_sig_t *x, spx_word16_t *y, spx_sig_t max_scale, int len);
+
+#endif
+
+
+#define HIGHPASS_NARROWBAND 0
+#define HIGHPASS_WIDEBAND 2
+#define HIGHPASS_INPUT 0
+#define HIGHPASS_OUTPUT 1
+#define HIGHPASS_IRS 4
+
+void highpass(const spx_word16_t *x, spx_word16_t *y, int len, int filtID, spx_mem_t *mem);
+
+
+void qmf_decomp(const spx_word16_t *xx, const spx_word16_t *aa, spx_word16_t *, spx_word16_t *y2, int N, int M, spx_word16_t *mem, char *stack);
+void qmf_synth(const spx_word16_t *x1, const spx_word16_t *x2, const spx_word16_t *a, spx_word16_t *y, int N, int M, spx_word32_t *mem1, spx_word32_t *mem2, char *stack);
+
+void filter_mem16(const spx_word16_t *x, const spx_coef_t *num, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack);
+void iir_mem16(const spx_word16_t *x, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack);
+void fir_mem16(const spx_word16_t *x, const spx_coef_t *num, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack);
+
+/* Apply bandwidth expansion on LPC coef */
+void bw_lpc(spx_word16_t , const spx_coef_t *lpc_in, spx_coef_t *lpc_out, int order);
+void sanitize_values32(spx_word32_t *vec, spx_word32_t min_val, spx_word32_t max_val, int len);
+
+
+void syn_percep_zero16(const spx_word16_t *xx, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack);
+void residue_percep_zero16(const spx_word16_t *xx, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack);
+
+void compute_impulse_response(const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack);
+
+void multicomb(
+spx_word16_t *exc,          /*decoded excitation*/
+spx_word16_t *new_exc,      /*enhanced excitation*/
+spx_coef_t *ak,           /*LPC filter coefs*/
+int p,               /*LPC order*/
+int nsf,             /*sub-frame size*/
+int pitch,           /*pitch period*/
+int max_pitch,   /*pitch gain (3-tap)*/
+spx_word16_t  comb_gain,    /*gain of comb filter*/
+char *stack
+);
+
+#endif
diff --git a/3rdparty/speex/libspeex/filters_arm4.h b/3rdparty/speex/libspeex/filters_arm4.h
new file mode 100644
index 0000000..9138610
--- /dev/null
+++ b/3rdparty/speex/libspeex/filters_arm4.h
@@ -0,0 +1,97 @@
+/* Copyright (C) 2004 Jean-Marc Valin */
+/**
+   @file filters_arm4.h
+   @brief Various analysis/synthesis filters (ARM4 version)
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define OVERRIDE_NORMALIZE16
+int normalize16(const spx_sig_t *x, spx_word16_t *y, int max_scale, int len)
+{
+   int i;
+   spx_sig_t max_val=1;
+   int sig_shift;
+   int dead1, dead2, dead3, dead4, dead5, dead6;
+
+   __asm__ __volatile__ (
+         "\tmov %1, #1 \n"
+         "\tmov %3, #0 \n"
+
+         ".normalize16loop1%=: \n"
+
+         "\tldr %4, [%0], #4 \n"
+         "\tcmps %4, %1 \n"
+         "\tmovgt %1, %4 \n"
+         "\tcmps %4, %3 \n"
+         "\tmovlt %3, %4 \n"
+
+         "\tsubs %2, %2, #1 \n"
+         "\tbne .normalize16loop1%=\n"
+
+         "\trsb %3, %3, #0 \n"
+         "\tcmp %1, %3 \n"
+         "\tmovlt %1, %3 \n"
+   : "=r" (dead1), "=r" (max_val), "=r" (dead3), "=r" (dead4),
+   "=r" (dead5), "=r" (dead6)
+   : "0" (x), "2" (len)
+   : "cc");
+
+   sig_shift=0;
+   while (max_val>max_scale)
+   {
+      sig_shift++;
+      max_val >>= 1;
+   }
+   
+   __asm__ __volatile__ (
+         ".normalize16loop%=: \n"
+
+         "\tldr %4, [%0], #4 \n"
+         "\tldr %5, [%0], #4 \n"
+         "\tmov %4, %4, asr %3 \n"
+         "\tstrh %4, [%1], #2 \n"
+         "\tldr %4, [%0], #4 \n"
+         "\tmov %5, %5, asr %3 \n"
+         "\tstrh %5, [%1], #2 \n"
+         "\tldr %5, [%0], #4 \n"
+         "\tmov %4, %4, asr %3 \n"
+         "\tstrh %4, [%1], #2 \n"
+         "\tsubs %2, %2, #1 \n"
+         "\tmov %5, %5, asr %3 \n"
+         "\tstrh %5, [%1], #2 \n"
+
+         "\tbge .normalize16loop%=\n"
+   : "=r" (dead1), "=r" (dead2), "=r" (dead3), "=r" (dead4),
+   "=r" (dead5), "=r" (dead6)
+   : "0" (x), "1" (y), "2" (len>>2), "3" (sig_shift)
+   : "cc", "memory");
+   return sig_shift;
+}
+
diff --git a/3rdparty/speex/libspeex/filters_bfin.h b/3rdparty/speex/libspeex/filters_bfin.h
new file mode 100644
index 0000000..1e433ee
--- /dev/null
+++ b/3rdparty/speex/libspeex/filters_bfin.h
@@ -0,0 +1,515 @@
+/* Copyright (C) 2005 Analog Devices */
+/**
+   @file filters_bfin.h
+   @brief Various analysis/synthesis filters (Blackfin version)
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define OVERRIDE_NORMALIZE16
+int normalize16(const spx_sig_t *x, spx_word16_t *y, spx_sig_t max_scale, int len)
+{
+   spx_sig_t max_val=1;
+   int sig_shift;
+   __asm__ 
+   (
+   "%0 = 0;\n\t"
+   "I0 = %1;\n\t"
+   "L0 = 0;\n\t"
+   "R1 = [I0++];\n\t"
+   "LOOP norm_max%= LC0 = %2;\n\t"
+   "LOOP_BEGIN norm_max%=;\n\t"
+      "R2 = ABS R1 || R1 = [I0++];\n\t"
+      "%0 = MAX(%0, R2);\n\t"
+   "LOOP_END norm_max%=;\n\t"
+   : "=&d" (max_val)
+   : "a" (x), "a" (len)
+   : "R1", "R2"
+   );
+
+   sig_shift=0;
+   while (max_val>max_scale)
+   {
+      sig_shift++;
+      max_val >>= 1;
+   }
+
+   __asm__ __volatile__ 
+   (
+   "I0 = %0;\n\t"
+   "L0 = 0;\n\t"
+   "P1 = %1;\n\t"
+   "R0 = [I0++];\n\t"
+   "LOOP norm_shift%= LC0 = %3;\n\t"
+   "LOOP_BEGIN norm_shift%=;\n\t"
+      "R1 = ASHIFT R0 by %2.L || R0 = [I0++];\n\t"
+      "W[P1++] = R1;\n\t"
+   "LOOP_END norm_shift%=;\n\t"
+   "R1 = ASHIFT R0 by %2.L;\n\t"
+   "W[P1++] = R1;\n\t"
+   : : "a" (x), "a" (y), "d" (-sig_shift), "a" (len-1)
+   : "I0", "L0", "P1", "R0", "R1", "memory"
+   );
+   return sig_shift;
+}
+
+
+
+#define OVERRIDE_FILTER_MEM16
+void filter_mem16(const spx_word16_t *_x, const spx_coef_t *num, const spx_coef_t *den, spx_word16_t *_y, int N, int ord, spx_mem_t *mem, char *stack)
+{
+   VARDECL(spx_word32_t *xy2);
+   VARDECL(spx_word32_t *numden_a);
+   spx_word32_t *xy;
+   spx_word16_t *numden;
+   int i;
+
+   ALLOC(xy2, (N+1), spx_word32_t);
+   ALLOC(numden_a, (2*ord+2), spx_word32_t);
+   xy = xy2+1;  
+   numden = (spx_word16_t*) numden_a;
+
+   for (i=0;i<ord;i++)
+   {
+      numden[2*i] = num[i];
+      numden[2*i+1] = den[i];
+   }
+   __asm__ __volatile__
+   (
+   /* Register setup */
+   "R0 = %5;\n\t"      /*ord */
+   
+   "P0 = %3;\n\t"
+   "I0 = P0;\n\t"
+   "B0 = P0;\n\t" /* numden */
+   "L0 = 0;\n\t"
+      
+   "P2 = %0;\n\t" /* Fused xy */
+   "I2 = P2;\n\t"
+   "L2 = 0;\n\t"
+   
+   "P4 = %6;\n\t" /* mem */
+   "P0 = %1;\n\t" /* _x */
+   "P1 = %2;\n\t" /* _y */
+   
+   /* First sample */
+   "R1 = [P4++];\n\t"
+   "R1 <<= 3;\n\t" /* shift mem */
+   "R1.L = R1 (RND);\n\t"
+   "R2 = W[P0++];\n\t" /* load x[0] */
+   "R1.L = R1.L + R2.L;\n\t"
+   "W[P1++] = R1;\n\t" /* store y[0] */
+   "R2 = PACK(R1.L, R2.L);\n\t" /* pack x16 and y16 */
+   "[P2] = R2;\n\t"
+               
+   /* Samples 1 to ord-1 (using memory) */
+   "R0 += -1;\n\t"
+   "R3 = 0;\n\t"
+   "LC0 = R0;\n\t"
+   "LOOP filter_start%= LC0;\n\t"
+   "LOOP_BEGIN filter_start%=;\n\t"
+      "R3 += 1;\n\t"
+      "LC1 = R3;\n\t"
+      
+      "R1 = [P4++];\n\t"
+      "A1 = R1;\n\t"
+      "A0 = 0;\n\t"
+      "I0 = B0;\n\t"
+      "I2 = P2;\n\t"
+      "P2 += 4;\n\t"
+      "R4 = [I0++] || R5 = [I2--];\n\t"
+      "LOOP filter_start_inner%= LC1;\n\t"
+      "LOOP_BEGIN filter_start_inner%=;\n\t"
+         "A1 -= R4.H*R5.H, A0 += R4.L*R5.L (IS) || R4 = [I0++] || R5 = [I2--];\n\t"
+      "LOOP_END filter_start_inner%=;\n\t"
+      "A0 += A1;\n\t"
+      "R4 = A0;\n\t"
+      "R4 <<= 3;\n\t" /* shift mem */
+      "R4.L = R4 (RND);\n\t"
+      "R2 = W[P0++];\n\t" /* load x */
+      "R4.L = R4.L + R2.L;\n\t"
+      "W[P1++] = R4;\n\t" /* store y */
+      //"R4 <<= 2;\n\t"
+      //"R2 <<= 2;\n\t"
+      "R2 = PACK(R4.L, R2.L);\n\t" /* pack x16 and y16 */
+      "[P2] = R2;\n\t"
+
+   "LOOP_END filter_start%=;\n\t"
+
+   /* Samples ord to N*/   
+   "R0 = %5;\n\t"
+   "R0 <<= 1;\n\t"
+   "I0 = B0;\n\t" /* numden */
+   "R0 <<= 1;\n\t"   
+   "L0 = R0;\n\t"
+   
+   "R0 = %5;\n\t" /* org */
+   "R2 = %4;\n\t" /* N */
+   "R2 = R2 - R0;\n\t"
+   "R4 = [I0++];\n\t" /* numden */
+   "LC0 = R2;\n\t"
+   "P3 = R0;\n\t"
+   "R0 <<= 2;\n\t"
+   "R0 += 8;\n\t"
+   "I2 = P2;\n\t"
+   "M0 = R0;\n\t"
+   "A1 = A0 = 0;\n\t"
+   "R5 = [I2--];\n\t" /* load xy */
+   "LOOP filter_mid%= LC0;\n\t"
+   "LOOP_BEGIN filter_mid%=;\n\t"
+      "LOOP filter_mid_inner%= LC1=P3;\n\t"
+      "LOOP_BEGIN filter_mid_inner%=;\n\t"
+         "A1 -= R4.H*R5.H, A0 += R4.L*R5.L (IS) || R4 = [I0++] || R5 = [I2--];\n\t"
+      "LOOP_END filter_mid_inner%=;\n\t"
+      "R0 = (A0 += A1) || I2 += M0;\n\t"
+      "R0 = R0 << 3 || R5 = W[P0++];\n\t" /* load x */
+      "R0.L = R0 (RND);\n\t"
+      "R0.L = R0.L + R5.L;\n\t"
+      "R5 = PACK(R0.L, R5.L) || W[P1++] = R0;\n\t" /* shift y | store y */
+      "A1 = A0 = 0 || [I2--] = R5\n\t"
+      "LOOP_END filter_mid%=;\n\t"
+   "I2 += 4;\n\t"
+   "P2 = I2;\n\t"
+   /* Update memory */
+   "P4 = %6;\n\t"
+   "R0 = %5;\n\t"
+   "LC0 = R0;\n\t"
+   "P0 = B0;\n\t"
+   "A1 = A0 = 0;\n\t"
+   "LOOP mem_update%= LC0;\n\t"
+   "LOOP_BEGIN mem_update%=;\n\t"
+      "I2 = P2;\n\t"
+      "I0 = P0;\n\t"
+      "P0 += 4;\n\t"
+      "R0 = LC0;\n\t"
+      "LC1 = R0;\n\t"
+      "R5 = [I2--] || R4 = [I0++];\n\t"
+      "LOOP mem_accum%= LC1;\n\t"
+      "LOOP_BEGIN mem_accum%=;\n\t"
+         "A1 -= R4.H*R5.H, A0 += R4.L*R5.L (IS) || R4 = [I0++] || R5 = [I2--];\n\t"
+      "LOOP_END mem_accum%=;\n\t"
+      "R0 = (A0 += A1);\n\t"
+      "A1 = A0 = 0 || [P4++] = R0;\n\t"
+   "LOOP_END mem_update%=;\n\t"
+   "L0 = 0;\n\t"
+   : : "m" (xy), "m" (_x), "m" (_y), "m" (numden), "m" (N), "m" (ord), "m" (mem)
+   : "A0", "A1", "R0", "R1", "R2", "R3", "R4", "R5", "P0", "P1", "P2", "P3", "P4", "B0", "I0", "I2", "L0", "L2", "M0", "memory"
+   );
+
+}
+
+
+
+#define OVERRIDE_IIR_MEM16
+void iir_mem16(const spx_word16_t *_x, const spx_coef_t *den, spx_word16_t *_y, int N, int ord, spx_mem_t *mem, char *stack)
+{
+   VARDECL(spx_word16_t *y);
+   spx_word16_t *yy;
+
+   ALLOC(y, (N+2), spx_word16_t);
+   yy = y+2;
+
+   __asm__ __volatile__
+   (
+   /* Register setup */
+   "R0 = %5;\n\t"      /*ord */
+   
+   "P1 = %3;\n\t"
+   "I1 = P1;\n\t"
+   "B1 = P1;\n\t"
+   "L1 = 0;\n\t"
+   
+   "P3 = %0;\n\t"
+   "I3 = P3;\n\t"
+   "L3 = 0;\n\t"
+   
+   "P4 = %6;\n\t"
+   "P0 = %1;\n\t"
+   "P1 = %2;\n\t"
+   
+   /* First sample */
+   "R1 = [P4++];\n\t"
+   "R1 = R1 << 3 (S);\n\t"
+   "R1.L = R1 (RND);\n\t"
+   "R2 = W[P0++];\n\t"
+   "R1 = R1 + R2;\n\t"
+   "W[P1++] = R1;\n\t"
+   "W[P3] = R1;\n\t"
+
+   /* Samples 1 to ord-1 (using memory) */
+   "R0 += -1;\n\t"
+   "R3 = 0;\n\t"
+   "LC0 = R0;\n\t"
+   "LOOP filter_start%= LC0;\n\t"
+   "LOOP_BEGIN filter_start%=;\n\t"
+      "R3 += 1;\n\t"
+      "LC1 = R3;\n\t"
+      
+      "R1 = [P4++];\n\t"
+      "A1 = R1;\n\t"
+      "I1 = B1;\n\t"
+      "I3 = P3;\n\t"
+      "P3 += 2;\n\t"
+      "LOOP filter_start_inner%= LC1;\n\t"
+      "LOOP_BEGIN filter_start_inner%=;\n\t"
+         "R4.L = W[I1++];\n\t"
+         "R5.L = W[I3--];\n\t"
+         "A1 -= R4.L*R5.L (IS);\n\t"
+      "LOOP_END filter_start_inner%=;\n\t"
+   
+      "R1 = A1;\n\t"
+      "R1 <<= 3;\n\t"
+      "R1.L = R1 (RND);\n\t"
+      "R2 = W[P0++];\n\t"
+      "R1 = R1 + R2;\n\t"
+      "W[P1++] = R1;\n\t"
+      "W[P3] = R1;\n\t"
+   "LOOP_END filter_start%=;\n\t"
+
+   /* Samples ord to N*/   
+   "R0 = %5;\n\t"
+   "R0 <<= 1;\n\t"
+   "I1 = B1;\n\t"
+   "L1 = R0;\n\t"
+   
+   "R0 = %5;\n\t"
+   "R2 = %4;\n\t"
+   "R2 = R2 - R0;\n\t"
+   "R4.L = W[I1++];\n\t"
+   "LC0 = R2;\n\t"
+   "LOOP filter_mid%= LC0;\n\t"
+   "LOOP_BEGIN filter_mid%=;\n\t"
+      "LC1 = R0;\n\t"
+      "A1 = 0;\n\t"
+      "I3 = P3;\n\t"
+      "P3 += 2;\n\t"
+      "R5.L = W[I3--];\n\t"
+      "LOOP filter_mid_inner%= LC1;\n\t"
+      "LOOP_BEGIN filter_mid_inner%=;\n\t"
+         "A1 -= R4.L*R5.L (IS) || R4.L = W[I1++] || R5.L = W[I3--];\n\t"
+      "LOOP_END filter_mid_inner%=;\n\t"
+      "R1 = A1;\n\t"
+      "R1 = R1 << 3 || R2 = W[P0++];\n\t"
+      "R1.L = R1 (RND);\n\t"
+      "R1 = R1 + R2;\n\t"
+      "W[P1++] = R1;\n\t"
+      "W[P3] = R1;\n\t"
+   "LOOP_END filter_mid%=;\n\t"
+     
+   /* Update memory */
+   "P4 = %6;\n\t"
+   "R0 = %5;\n\t"
+   "LC0 = R0;\n\t"
+   "P1 = B1;\n\t"
+   "LOOP mem_update%= LC0;\n\t"
+   "LOOP_BEGIN mem_update%=;\n\t"
+      "A0 = 0;\n\t"
+      "I3 = P3;\n\t"
+      "I1 = P1;\n\t"
+      "P1 += 2;\n\t"
+      "R0 = LC0;\n\t"
+      "LC1=R0;\n\t"
+      "R5.L = W[I3--] || R4.L = W[I1++];\n\t"
+      "LOOP mem_accum%= LC1;\n\t"
+      "LOOP_BEGIN mem_accum%=;\n\t"
+         "A0 -= R4.L*R5.L (IS) || R4.L = W[I1++] || R5.L = W[I3--];\n\t"
+      "LOOP_END mem_accum%=;\n\t"
+      "R0 = A0;\n\t"
+      "[P4++] = R0;\n\t"
+   "LOOP_END mem_update%=;\n\t"
+   "L1 = 0;\n\t"
+   : : "m" (yy), "m" (_x), "m" (_y), "m" (den), "m" (N), "m" (ord), "m" (mem)
+   : "A0", "A1", "R0", "R1", "R2", "R3", "R4", "R5", "P0", "P1", "P2", "P3", "P4", "B1", "I1", "I3", "L1", "L3", "memory"
+   );
+
+}
+
+
+#define OVERRIDE_FIR_MEM16
+void fir_mem16(const spx_word16_t *x, const spx_coef_t *num, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack)
+{
+   int i;
+   spx_coef_t den2[12];
+   spx_coef_t *den;
+   den = (spx_coef_t*)((((int)den2)+4)&0xfffffffc);
+   for (i=0;i<10;i++)
+      den[i] = 0;
+   filter_mem16(x, num, den, y, N, ord, mem, stack);
+}
+
+
+#define OVERRIDE_COMPUTE_IMPULSE_RESPONSE
+void compute_impulse_response(const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack)
+{
+   int i;
+   VARDECL(spx_word16_t *ytmp);
+   ALLOC(ytmp, N, spx_word16_t);
+   spx_word16_t *ytmp2 = ytmp;
+   y[0] = LPC_SCALING;
+   for (i=0;i<ord;i++)
+      y[i+1] = awk1[i];
+   i++;
+   for (;i<N;i++)
+      y[i] = 0;
+
+   N-=1;
+   __asm__ __volatile__
+   (
+         "I0 = %0;\n\t"
+         "I1 = %1;\n\t"
+         "L0 = 0;\n\t"
+         "L1 = 0;\n\t"
+         "L2 = 0;\n\t"
+         "L3 = 0;\n\t"
+         "R0 = 1;\n\t"
+         "R0 <<= 13;\n\t"
+         "W[I0] = R0.L;\n\t"
+         "R0 <<= 1;\n\t"
+         "W[I1] = R0.L;\n\t"
+         "R0 = %5;\n\t"
+         "LC0 = R0;\n\t"
+         "R2 = 0;\n\t"
+         "LOOP samples%= LC0;\n\t"
+         "LOOP_BEGIN samples%=;\n\t"
+            "R2 += 1;\n\t"
+            "R2 = MIN(R2, %4);\n\t"
+            "I0 = %0;\n\t"
+            "I1 = %1;\n\t"
+            "I2 = %2;\n\t"
+            "I3 = %3;\n\t"
+            "%0 += 2;\n\t"
+            "%1 += 2;\n\t"
+            "A1 = A0 = 0;\n\t"
+            "R0.L = W[I0--] || R1.L = W[I2++];\n\t"
+            "LC1 = R2;\n\t"
+            "LOOP filter%= LC1;\n\t"
+            "LOOP_BEGIN filter%=;\n\t"
+               "A0 -= R0.L*R1.L (IS) || R0.L = W[I1--] || R1.L = W[I3++];\n\t"
+               "A1 -= R0.L*R1.L (IS) || R0.L = W[I0--] || R1.L = W[I2++];\n\t"
+            "LOOP_END filter%=;\n\t"
+            "R0 = A0, R1 = A1;\n\t"
+            "R3 = W[%1] (X);\n\t"
+            "R3 <<= 13;\n\t"
+            "R0 = R0 + R3;\n\t"
+            "R3 = R0 >>> 13;\n\t"
+            "W[%0] = R3.L;\n\t"
+            "R0 <<= 1;\n\t"
+            "R1 = R1 + R0;\n\t"
+            "R1 >>>= 13;\n\t"
+            "W[%1] = R1.L;\n\t"
+         "LOOP_END samples%=;\n\t"
+   : "=a" (ytmp2), "=a" (y)
+   : "a" (awk2), "a" (ak), "d" (ord), "m" (N), "0" (ytmp2), "1" (y)
+   : "A0", "A1", "R0", "R1", "R2", "R3", "I0", "I1", "I2", "I3", "L0", "L1", "L2", "L3", "A0", "A1"
+   );
+}
+
+
+
+#if 0 /* Equivalent C function for filter_mem2 and compute_impulse_response */
+#define min(a,b) ((a)<(b) ? (a):(b))
+
+void compute_impulse_response(const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack)
+{
+   int i,j;
+   VARDECL(spx_word16_t *ytmp);
+   ALLOC(ytmp, N, spx_word16_t);
+   
+   y[0] = LPC_SCALING;
+   for (i=0;i<ord;i++)
+      y[i+1] = awk1[i];
+   i++;
+   for (;i<N;i++)
+      y[i] = 0;
+
+   for (i=0;i<N;i++)
+   {
+      spx_word32_t yi = SHL32(EXTEND32(y[i]),LPC_SHIFT);
+      spx_word32_t yi2 = 0;
+      for (j=0;j<min(i,ord);j++)
+      {
+         yi = MAC16_16(yi, awk2[j], -ytmp[i-j-1]);
+         yi2 = MAC16_16(yi2, ak[j], -y[i-j-1]);
+      }
+      ytmp[i] = EXTRACT16(SHR32(yi,LPC_SHIFT));
+      yi2 = ADD32(yi2,SHL32(yi,1));
+      y[i] = EXTRACT16(SHR32(yi2,LPC_SHIFT));
+   }
+
+}
+
+
+void filter_mem2(const spx_sig_t *_x, const spx_coef_t *num, const spx_coef_t *den, spx_sig_t *_y, int N, int ord, spx_mem_t *mem)
+{
+   int i,j;
+   spx_word16_t xi,yi,nyi;
+   spx_word16_t x[N],y[N];
+   spx_word16_t *xx, *yy;
+   xx = x;
+   yy = y;
+   for (i=0;i<N;i++)
+   {
+      x[i] = EXTRACT16(SHR32(_x[i],SIG_SHIFT));
+   }
+   
+   for (i=0;i<ord;i++)
+   {
+      spx_word32_t yi = mem[i];
+      for (j=0;j<i;j++)
+      {
+         yi = MAC16_16(yi, num[j], x[i-j-1]);
+         yi = MAC16_16(yi, den[j], -y[i-j-1]);
+      }
+      _y[i] = ADD32(_x[i],SHL32(yi,1));
+      y[i] = EXTRACT16(SHR32(_y[i],SIG_SHIFT));
+   }
+   for (i=ord;i<N;i++)
+   {
+      spx_word32_t yi = 0;
+      for (j=0;j<ord;j++)
+      {
+         yi = MAC16_16(yi, num[j], x[i-j-1]);
+         yi = MAC16_16(yi, den[j], -y[i-j-1]);
+      }
+      _y[i] = ADD32(_x[i],SHL32(yi,1));
+      y[i] = EXTRACT16(SHR32(_y[i],SIG_SHIFT));
+   }
+
+   for (i=0;i<ord;i++)
+   {
+      spx_mem_t m = 0;
+      for (j=0;j<ord-i;j++)
+      {
+         m = MAC16_16(m, x[N-1-j], num[j+i]);
+         m = MAC16_16(m, -y[N-1-j], den[j+i]);
+      }
+      mem[i] = m;
+   }
+}
+#endif
diff --git a/3rdparty/speex/libspeex/filters_sse.h b/3rdparty/speex/libspeex/filters_sse.h
new file mode 100644
index 0000000..4bb333d
--- /dev/null
+++ b/3rdparty/speex/libspeex/filters_sse.h
@@ -0,0 +1,336 @@
+/* Copyright (C) 2002 Jean-Marc Valin */
+/**
+   @file filters_sse.h
+   @brief Various analysis/synthesis filters (SSE version)
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <xmmintrin.h>
+
+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];
+
+   int i;
+
+   /* Copy numerator, denominator and memory to aligned xmm */
+   for (i=0;i<2;i++)
+   {
+      mem[i] = _mm_loadu_ps(_mem+4*i);
+      num[i] = _mm_loadu_ps(_num+4*i);
+      den[i] = _mm_loadu_ps(_den+4*i);
+   }
+   mem[2] = _mm_setr_ps(_mem[8], _mem[9], 0, 0);
+   num[2] = _mm_setr_ps(_num[8], _num[9], 0, 0);
+   den[2] = _mm_setr_ps(_den[8], _den[9], 0, 0);
+   
+   for (i=0;i<N;i++)
+   {
+      __m128 xx;
+      __m128 yy;
+      /* Compute next filter result */
+      xx = _mm_load_ps1(x+i);
+      yy = _mm_add_ss(xx, mem[0]);
+      _mm_store_ss(y+i, yy);
+      yy = _mm_shuffle_ps(yy, yy, 0);
+      
+      /* Update memory */
+      mem[0] = _mm_move_ss(mem[0], mem[1]);
+      mem[0] = _mm_shuffle_ps(mem[0], mem[0], 0x39);
+
+      mem[0] = _mm_add_ps(mem[0], _mm_mul_ps(xx, num[0]));
+      mem[0] = _mm_sub_ps(mem[0], _mm_mul_ps(yy, den[0]));
+
+      mem[1] = _mm_move_ss(mem[1], mem[2]);
+      mem[1] = _mm_shuffle_ps(mem[1], mem[1], 0x39);
+
+      mem[1] = _mm_add_ps(mem[1], _mm_mul_ps(xx, num[1]));
+      mem[1] = _mm_sub_ps(mem[1], _mm_mul_ps(yy, den[1]));
+
+      mem[2] = _mm_shuffle_ps(mem[2], mem[2], 0xfd);
+
+      mem[2] = _mm_add_ps(mem[2], _mm_mul_ps(xx, num[2]));
+      mem[2] = _mm_sub_ps(mem[2], _mm_mul_ps(yy, den[2]));
+   }
+   /* Put memory back in its place */
+   _mm_storeu_ps(_mem, mem[0]);
+   _mm_storeu_ps(_mem+4, mem[1]);
+   _mm_store_ss(_mem+8, mem[2]);
+   mem[2] = _mm_shuffle_ps(mem[2], mem[2], 0x55);
+   _mm_store_ss(_mem+9, mem[2]);
+}
+
+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];
+
+   int i;
+
+   /* Copy numerator, denominator and memory to aligned xmm */
+   for (i=0;i<2;i++)
+   {
+      mem[i] = _mm_loadu_ps(_mem+4*i);
+      num[i] = _mm_loadu_ps(_num+4*i);
+      den[i] = _mm_loadu_ps(_den+4*i);
+   }
+   
+   for (i=0;i<N;i++)
+   {
+      __m128 xx;
+      __m128 yy;
+      /* Compute next filter result */
+      xx = _mm_load_ps1(x+i);
+      yy = _mm_add_ss(xx, mem[0]);
+      _mm_store_ss(y+i, yy);
+      yy = _mm_shuffle_ps(yy, yy, 0);
+      
+      /* Update memory */
+      mem[0] = _mm_move_ss(mem[0], mem[1]);
+      mem[0] = _mm_shuffle_ps(mem[0], mem[0], 0x39);
+
+      mem[0] = _mm_add_ps(mem[0], _mm_mul_ps(xx, num[0]));
+      mem[0] = _mm_sub_ps(mem[0], _mm_mul_ps(yy, den[0]));
+
+      mem[1] = _mm_sub_ss(mem[1], mem[1]);
+      mem[1] = _mm_shuffle_ps(mem[1], mem[1], 0x39);
+
+      mem[1] = _mm_add_ps(mem[1], _mm_mul_ps(xx, num[1]));
+      mem[1] = _mm_sub_ps(mem[1], _mm_mul_ps(yy, den[1]));
+   }
+   /* Put memory back in its place */
+   _mm_storeu_ps(_mem, mem[0]);
+   _mm_storeu_ps(_mem+4, mem[1]);
+}
+
+
+#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_mem16_10(x, _num, _den, y, N, ord, _mem);
+   else if (ord==8)
+      filter_mem16_8(x, _num, _den, y, N, ord, _mem);
+}
+
+
+
+void iir_mem16_10(const float *x, const float *_den, float *y, int N, int ord, float *_mem)
+{
+   __m128 den[3], mem[3];
+
+   int i;
+
+   /* Copy numerator, denominator and memory to aligned xmm */
+   for (i=0;i<2;i++)
+   {
+      mem[i] = _mm_loadu_ps(_mem+4*i);
+      den[i] = _mm_loadu_ps(_den+4*i);
+   }
+   mem[2] = _mm_setr_ps(_mem[8], _mem[9], 0, 0);
+   den[2] = _mm_setr_ps(_den[8], _den[9], 0, 0);
+   
+   for (i=0;i<N;i++)
+   {
+      __m128 xx;
+      __m128 yy;
+      /* Compute next filter result */
+      xx = _mm_load_ps1(x+i);
+      yy = _mm_add_ss(xx, mem[0]);
+      _mm_store_ss(y+i, yy);
+      yy = _mm_shuffle_ps(yy, yy, 0);
+      
+      /* Update memory */
+      mem[0] = _mm_move_ss(mem[0], mem[1]);
+      mem[0] = _mm_shuffle_ps(mem[0], mem[0], 0x39);
+
+      mem[0] = _mm_sub_ps(mem[0], _mm_mul_ps(yy, den[0]));
+
+      mem[1] = _mm_move_ss(mem[1], mem[2]);
+      mem[1] = _mm_shuffle_ps(mem[1], mem[1], 0x39);
+
+      mem[1] = _mm_sub_ps(mem[1], _mm_mul_ps(yy, den[1]));
+
+      mem[2] = _mm_shuffle_ps(mem[2], mem[2], 0xfd);
+
+      mem[2] = _mm_sub_ps(mem[2], _mm_mul_ps(yy, den[2]));
+   }
+   /* Put memory back in its place */
+   _mm_storeu_ps(_mem, mem[0]);
+   _mm_storeu_ps(_mem+4, mem[1]);
+   _mm_store_ss(_mem+8, mem[2]);
+   mem[2] = _mm_shuffle_ps(mem[2], mem[2], 0x55);
+   _mm_store_ss(_mem+9, mem[2]);
+}
+
+
+void iir_mem16_8(const float *x, const float *_den, float *y, int N, int ord, float *_mem)
+{
+   __m128 den[2], mem[2];
+
+   int i;
+
+   /* Copy numerator, denominator and memory to aligned xmm */
+   for (i=0;i<2;i++)
+   {
+      mem[i] = _mm_loadu_ps(_mem+4*i);
+      den[i] = _mm_loadu_ps(_den+4*i);
+   }
+   
+   for (i=0;i<N;i++)
+   {
+      __m128 xx;
+      __m128 yy;
+      /* Compute next filter result */
+      xx = _mm_load_ps1(x+i);
+      yy = _mm_add_ss(xx, mem[0]);
+      _mm_store_ss(y+i, yy);
+      yy = _mm_shuffle_ps(yy, yy, 0);
+      
+      /* Update memory */
+      mem[0] = _mm_move_ss(mem[0], mem[1]);
+      mem[0] = _mm_shuffle_ps(mem[0], mem[0], 0x39);
+
+      mem[0] = _mm_sub_ps(mem[0], _mm_mul_ps(yy, den[0]));
+
+      mem[1] = _mm_sub_ss(mem[1], mem[1]);
+      mem[1] = _mm_shuffle_ps(mem[1], mem[1], 0x39);
+
+      mem[1] = _mm_sub_ps(mem[1], _mm_mul_ps(yy, den[1]));
+   }
+   /* Put memory back in its place */
+   _mm_storeu_ps(_mem, mem[0]);
+   _mm_storeu_ps(_mem+4, mem[1]);
+}
+
+#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_mem16_10(x, _den, y, N, ord, _mem);
+   else if (ord==8)
+      iir_mem16_8(x, _den, y, N, ord, _mem);
+}
+
+
+void fir_mem16_10(const float *x, const float *_num, float *y, int N, int ord, float *_mem)
+{
+   __m128 num[3], mem[3];
+
+   int i;
+
+   /* Copy numerator, denominator and memory to aligned xmm */
+   for (i=0;i<2;i++)
+   {
+      mem[i] = _mm_loadu_ps(_mem+4*i);
+      num[i] = _mm_loadu_ps(_num+4*i);
+   }
+   mem[2] = _mm_setr_ps(_mem[8], _mem[9], 0, 0);
+   num[2] = _mm_setr_ps(_num[8], _num[9], 0, 0);
+   
+   for (i=0;i<N;i++)
+   {
+      __m128 xx;
+      __m128 yy;
+      /* Compute next filter result */
+      xx = _mm_load_ps1(x+i);
+      yy = _mm_add_ss(xx, mem[0]);
+      _mm_store_ss(y+i, yy);
+      yy = _mm_shuffle_ps(yy, yy, 0);
+      
+      /* Update memory */
+      mem[0] = _mm_move_ss(mem[0], mem[1]);
+      mem[0] = _mm_shuffle_ps(mem[0], mem[0], 0x39);
+
+      mem[0] = _mm_add_ps(mem[0], _mm_mul_ps(xx, num[0]));
+
+      mem[1] = _mm_move_ss(mem[1], mem[2]);
+      mem[1] = _mm_shuffle_ps(mem[1], mem[1], 0x39);
+
+      mem[1] = _mm_add_ps(mem[1], _mm_mul_ps(xx, num[1]));
+
+      mem[2] = _mm_shuffle_ps(mem[2], mem[2], 0xfd);
+
+      mem[2] = _mm_add_ps(mem[2], _mm_mul_ps(xx, num[2]));
+   }
+   /* Put memory back in its place */
+   _mm_storeu_ps(_mem, mem[0]);
+   _mm_storeu_ps(_mem+4, mem[1]);
+   _mm_store_ss(_mem+8, mem[2]);
+   mem[2] = _mm_shuffle_ps(mem[2], mem[2], 0x55);
+   _mm_store_ss(_mem+9, mem[2]);
+}
+
+void fir_mem16_8(const float *x, const float *_num, float *y, int N, int ord, float *_mem)
+{
+   __m128 num[2], mem[2];
+
+   int i;
+
+   /* Copy numerator, denominator and memory to aligned xmm */
+   for (i=0;i<2;i++)
+   {
+      mem[i] = _mm_loadu_ps(_mem+4*i);
+      num[i] = _mm_loadu_ps(_num+4*i);
+   }
+   
+   for (i=0;i<N;i++)
+   {
+      __m128 xx;
+      __m128 yy;
+      /* Compute next filter result */
+      xx = _mm_load_ps1(x+i);
+      yy = _mm_add_ss(xx, mem[0]);
+      _mm_store_ss(y+i, yy);
+      yy = _mm_shuffle_ps(yy, yy, 0);
+      
+      /* Update memory */
+      mem[0] = _mm_move_ss(mem[0], mem[1]);
+      mem[0] = _mm_shuffle_ps(mem[0], mem[0], 0x39);
+
+      mem[0] = _mm_add_ps(mem[0], _mm_mul_ps(xx, num[0]));
+
+      mem[1] = _mm_sub_ss(mem[1], mem[1]);
+      mem[1] = _mm_shuffle_ps(mem[1], mem[1], 0x39);
+
+      mem[1] = _mm_add_ps(mem[1], _mm_mul_ps(xx, num[1]));
+   }
+   /* Put memory back in its place */
+   _mm_storeu_ps(_mem, mem[0]);
+   _mm_storeu_ps(_mem+4, mem[1]);
+}
+
+#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_mem16_10(x, _num, y, N, ord, _mem);
+   else if (ord==8)
+      fir_mem16_8(x, _num, y, N, ord, _mem);
+}
diff --git a/3rdparty/speex/libspeex/fixed_arm4.h b/3rdparty/speex/libspeex/fixed_arm4.h
new file mode 100644
index 0000000..b6981ca
--- /dev/null
+++ b/3rdparty/speex/libspeex/fixed_arm4.h
@@ -0,0 +1,148 @@
+/* Copyright (C) 2004 Jean-Marc Valin */
+/**
+   @file fixed_arm4.h
+   @brief ARM4 fixed-point operations
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FIXED_ARM4_H
+#define FIXED_ARM4_H
+
+#undef MULT16_32_Q14
+static inline spx_word32_t MULT16_32_Q14(spx_word16_t x, spx_word32_t y) {
+  int res;
+  int dummy;
+  asm (
+        "smull  %0,%1,%2,%3 \n\t"
+        "mov %0, %0, lsr #14 \n\t"
+        "add %0, %0, %1, lsl #18 \n\t"
+   : "=&r"(res), "=&r" (dummy)
+   : "r"(y),"r"((int)x));
+  return(res);
+}
+
+#undef MULT16_32_Q15
+static inline spx_word32_t MULT16_32_Q15(spx_word16_t x, spx_word32_t y) {
+  int res;
+  int dummy;
+  asm (
+        "smull  %0,%1,%2,%3 \n\t"
+        "mov %0, %0, lsr #15 \n\t"
+        "add %0, %0, %1, lsl #17 \n\t"
+   : "=&r"(res), "=&r" (dummy)
+   : "r"(y),"r"((int)x));
+  return(res);
+}
+
+#undef DIV32_16
+static inline short DIV32_16(int a, int b)
+{
+   int res=0;
+   int dead1, dead2, dead3, dead4, dead5;
+   __asm__ __volatile__ (
+         "\teor %5, %0, %1\n"
+         "\tmovs %4, %0\n"
+         "\trsbmi %0, %0, #0 \n"
+         "\tmovs %4, %1\n"
+         "\trsbmi %1, %1, #0 \n"
+         "\tmov %4, #1\n"
+
+         "\tsubs %3, %0, %1, asl #14 \n"
+         "\tmovpl %0, %3 \n"
+         "\torrpl %2, %2, %4, asl #14 \n"
+
+         "\tsubs %3, %0, %1, asl #13 \n"
+         "\tmovpl %0, %3 \n"
+         "\torrpl %2, %2, %4, asl #13 \n"
+
+         "\tsubs %3, %0, %1, asl #12 \n"
+         "\tmovpl %0, %3 \n"
+         "\torrpl %2, %2, %4, asl #12 \n"
+
+         "\tsubs %3, %0, %1, asl #11 \n"
+         "\tmovpl %0, %3 \n"
+         "\torrpl %2, %2, %4, asl #11 \n"
+
+         "\tsubs %3, %0, %1, asl #10 \n"
+         "\tmovpl %0, %3 \n"
+         "\torrpl %2, %2, %4, asl #10 \n"
+
+         "\tsubs %3, %0, %1, asl #9 \n"
+         "\tmovpl %0, %3 \n"
+         "\torrpl %2, %2, %4, asl #9 \n"
+
+         "\tsubs %3, %0, %1, asl #8 \n"
+         "\tmovpl %0, %3 \n"
+         "\torrpl %2, %2, %4, asl #8 \n"
+
+         "\tsubs %3, %0, %1, asl #7 \n"
+         "\tmovpl %0, %3 \n"
+         "\torrpl %2, %2, %4, asl #7 \n"
+
+         "\tsubs %3, %0, %1, asl #6 \n"
+         "\tmovpl %0, %3 \n"
+         "\torrpl %2, %2, %4, asl #6 \n"
+         
+         "\tsubs %3, %0, %1, asl #5 \n"
+         "\tmovpl %0, %3 \n"
+         "\torrpl %2, %2, %4, asl #5 \n"
+
+         "\tsubs %3, %0, %1, asl #4 \n"
+         "\tmovpl %0, %3 \n"
+         "\torrpl %2, %2, %4, asl #4 \n"
+
+         "\tsubs %3, %0, %1, asl #3 \n"
+         "\tmovpl %0, %3 \n"
+         "\torrpl %2, %2, %4, asl #3 \n"
+
+         "\tsubs %3, %0, %1, asl #2 \n"
+         "\tmovpl %0, %3 \n"
+         "\torrpl %2, %2, %4, asl #2 \n"
+
+         "\tsubs %3, %0, %1, asl #1 \n"
+         "\tmovpl %0, %3 \n"
+         "\torrpl %2, %2, %4, asl #1 \n"
+
+         "\tsubs %3, %0, %1 \n"
+         "\tmovpl %0, %3 \n"
+         "\torrpl %2, %2, %4 \n"
+
+         "\tmovs %5, %5, lsr #31 \n"
+         "\trsbne %2, %2, #0 \n"
+   : "=r" (dead1), "=r" (dead2), "=r" (res),
+   "=r" (dead3), "=r" (dead4), "=r" (dead5)
+   : "0" (a), "1" (b), "2" (res)
+   : "cc"
+                        );
+   return res;
+}
+
+
+#endif
diff --git a/3rdparty/speex/libspeex/fixed_arm5e.h b/3rdparty/speex/libspeex/fixed_arm5e.h
new file mode 100644
index 0000000..9b4861c
--- /dev/null
+++ b/3rdparty/speex/libspeex/fixed_arm5e.h
@@ -0,0 +1,178 @@
+/* Copyright (C) 2003 Jean-Marc Valin */
+/**
+   @file fixed_arm5e.h
+   @brief ARM-tuned fixed-point operations
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FIXED_ARM5E_H
+#define FIXED_ARM5E_H
+
+#undef MULT16_16
+static inline spx_word32_t MULT16_16(spx_word16_t x, spx_word16_t y) {
+  int res;
+  asm ("smulbb  %0,%1,%2;\n"
+              : "=&r"(res)
+              : "%r"(x),"r"(y));
+  return(res);
+}
+
+#undef MAC16_16
+static inline spx_word32_t MAC16_16(spx_word32_t a, spx_word16_t x, spx_word32_t y) {
+  int res;
+  asm ("smlabb  %0,%1,%2,%3;\n"
+              : "=&r"(res)
+               : "%r"(x),"r"(y),"r"(a));
+  return(res);
+}
+
+#undef MULT16_32_Q15
+static inline spx_word32_t MULT16_32_Q15(spx_word16_t x, spx_word32_t y) {
+  int res;
+  asm ("smulwb  %0,%1,%2;\n"
+              : "=&r"(res)
+               : "%r"(y<<1),"r"(x));
+  return(res);
+}
+
+#undef MAC16_32_Q15
+static inline spx_word32_t MAC16_32_Q15(spx_word32_t a, spx_word16_t x, spx_word32_t y) {
+  int res;
+  asm ("smlawb  %0,%1,%2,%3;\n"
+              : "=&r"(res)
+               : "%r"(y<<1),"r"(x),"r"(a));
+  return(res);
+}
+
+#undef MULT16_32_Q11
+static inline spx_word32_t MULT16_32_Q11(spx_word16_t x, spx_word32_t y) {
+  int res;
+  asm ("smulwb  %0,%1,%2;\n"
+              : "=&r"(res)
+               : "%r"(y<<5),"r"(x));
+  return(res);
+}
+
+#undef MAC16_32_Q11
+static inline spx_word32_t MAC16_32_Q11(spx_word32_t a, spx_word16_t x, spx_word32_t y) {
+  int res;
+  asm ("smlawb  %0,%1,%2,%3;\n"
+              : "=&r"(res)
+               : "%r"(y<<5),"r"(x),"r"(a));
+  return(res);
+}
+
+#undef DIV32_16
+static inline short DIV32_16(int a, int b)
+{
+   int res=0;
+   int dead1, dead2, dead3, dead4, dead5;
+   __asm__ __volatile__ (
+         "\teor %5, %0, %1\n"
+         "\tmovs %4, %0\n"
+         "\trsbmi %0, %0, #0 \n"
+         "\tmovs %4, %1\n"
+         "\trsbmi %1, %1, #0 \n"
+         "\tmov %4, #1\n"
+
+         "\tsubs %3, %0, %1, asl #14 \n"
+         "\torrpl %2, %2, %4, asl #14 \n"
+         "\tmovpl %0, %3 \n"
+
+         "\tsubs %3, %0, %1, asl #13 \n"
+         "\torrpl %2, %2, %4, asl #13 \n"
+         "\tmovpl %0, %3 \n"
+
+         "\tsubs %3, %0, %1, asl #12 \n"
+         "\torrpl %2, %2, %4, asl #12 \n"
+         "\tmovpl %0, %3 \n"
+
+         "\tsubs %3, %0, %1, asl #11 \n"
+         "\torrpl %2, %2, %4, asl #11 \n"
+         "\tmovpl %0, %3 \n"
+
+         "\tsubs %3, %0, %1, asl #10 \n"
+         "\torrpl %2, %2, %4, asl #10 \n"
+         "\tmovpl %0, %3 \n"
+
+         "\tsubs %3, %0, %1, asl #9 \n"
+         "\torrpl %2, %2, %4, asl #9 \n"
+         "\tmovpl %0, %3 \n"
+
+         "\tsubs %3, %0, %1, asl #8 \n"
+         "\torrpl %2, %2, %4, asl #8 \n"
+         "\tmovpl %0, %3 \n"
+
+         "\tsubs %3, %0, %1, asl #7 \n"
+         "\torrpl %2, %2, %4, asl #7 \n"
+         "\tmovpl %0, %3 \n"
+
+         "\tsubs %3, %0, %1, asl #6 \n"
+         "\torrpl %2, %2, %4, asl #6 \n"
+         "\tmovpl %0, %3 \n"
+
+         "\tsubs %3, %0, %1, asl #5 \n"
+         "\torrpl %2, %2, %4, asl #5 \n"
+         "\tmovpl %0, %3 \n"
+
+         "\tsubs %3, %0, %1, asl #4 \n"
+         "\torrpl %2, %2, %4, asl #4 \n"
+         "\tmovpl %0, %3 \n"
+
+         "\tsubs %3, %0, %1, asl #3 \n"
+         "\torrpl %2, %2, %4, asl #3 \n"
+         "\tmovpl %0, %3 \n"
+
+         "\tsubs %3, %0, %1, asl #2 \n"
+         "\torrpl %2, %2, %4, asl #2 \n"
+         "\tmovpl %0, %3 \n"
+
+         "\tsubs %3, %0, %1, asl #1 \n"
+         "\torrpl %2, %2, %4, asl #1 \n"
+         "\tmovpl %0, %3 \n"
+
+         "\tsubs %3, %0, %1 \n"
+         "\torrpl %2, %2, %4 \n"
+         "\tmovpl %0, %3 \n"
+         
+         "\tmovs %5, %5, lsr #31 \n"
+         "\trsbne %2, %2, #0 \n"
+   : "=r" (dead1), "=r" (dead2), "=r" (res),
+   "=r" (dead3), "=r" (dead4), "=r" (dead5)
+   : "0" (a), "1" (b), "2" (res)
+   : "memory", "cc"
+                        );
+   return res;
+}
+
+
+
+
+#endif
diff --git a/3rdparty/speex/libspeex/fixed_bfin.h b/3rdparty/speex/libspeex/fixed_bfin.h
new file mode 100644
index 0000000..aa26f6a
--- /dev/null
+++ b/3rdparty/speex/libspeex/fixed_bfin.h
@@ -0,0 +1,173 @@
+/* Copyright (C) 2005 Analog Devices
+   Author: Jean-Marc Valin */
+/**
+   @file fixed_bfin.h
+   @brief Blackfin fixed-point operations
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FIXED_BFIN_H
+#define FIXED_BFIN_H
+
+#undef PDIV32_16
+static inline spx_word16_t PDIV32_16(spx_word32_t a, spx_word16_t b)
+{
+   spx_word32_t res, bb;
+   bb = b;
+   a += b>>1;
+   __asm__  (
+         "P0 = 15;\n\t"
+         "R0 = %1;\n\t"
+         "R1 = %2;\n\t"
+         //"R0 = R0 + R1;\n\t"
+         "R0 <<= 1;\n\t"
+         "DIVS (R0, R1);\n\t"
+         "LOOP divide%= LC0 = P0;\n\t"
+         "LOOP_BEGIN divide%=;\n\t"
+            "DIVQ (R0, R1);\n\t"
+         "LOOP_END divide%=;\n\t"
+         "R0 = R0.L;\n\t"
+         "%0 = R0;\n\t"
+   : "=m" (res)
+   : "m" (a), "m" (bb)
+   : "P0", "R0", "R1", "cc");
+   return res;
+}
+
+#undef DIV32_16
+static inline spx_word16_t DIV32_16(spx_word32_t a, spx_word16_t b)
+{
+   spx_word32_t res, bb;
+   bb = b;
+   /* Make the roundinf consistent with the C version 
+      (do we need to do that?)*/
+   if (a<0) 
+      a += (b-1);
+   __asm__  (
+         "P0 = 15;\n\t"
+         "R0 = %1;\n\t"
+         "R1 = %2;\n\t"
+         "R0 <<= 1;\n\t"
+         "DIVS (R0, R1);\n\t"
+         "LOOP divide%= LC0 = P0;\n\t"
+         "LOOP_BEGIN divide%=;\n\t"
+            "DIVQ (R0, R1);\n\t"
+         "LOOP_END divide%=;\n\t"
+         "R0 = R0.L;\n\t"
+         "%0 = R0;\n\t"
+   : "=m" (res)
+   : "m" (a), "m" (bb)
+   : "P0", "R0", "R1", "cc");
+   return res;
+}
+
+#undef MAX16
+static inline spx_word16_t MAX16(spx_word16_t a, spx_word16_t b)
+{
+   spx_word32_t res;
+   __asm__  (
+         "%1 = %1.L (X);\n\t"
+         "%2 = %2.L (X);\n\t"
+         "%0 = MAX(%1,%2);"
+   : "=d" (res)
+   : "%d" (a), "d" (b)
+   );
+   return res;
+}
+
+#undef MULT16_32_Q15
+static inline spx_word32_t MULT16_32_Q15(spx_word16_t a, spx_word32_t b)
+{
+   spx_word32_t res;
+   __asm__
+   (
+         "A1 = %2.L*%1.L (M);\n\t"
+         "A1 = A1 >>> 15;\n\t"
+         "%0 = (A1 += %2.L*%1.H) ;\n\t"
+   : "=&W" (res), "=&d" (b)
+   : "d" (a), "1" (b)
+   : "A1"
+   );
+   return res;
+}
+
+#undef MAC16_32_Q15
+static inline spx_word32_t MAC16_32_Q15(spx_word32_t c, spx_word16_t a, spx_word32_t b)
+{
+   spx_word32_t res;
+   __asm__
+         (
+         "A1 = %2.L*%1.L (M);\n\t"
+         "A1 = A1 >>> 15;\n\t"
+         "%0 = (A1 += %2.L*%1.H);\n\t"
+         "%0 = %0 + %4;\n\t"
+   : "=&W" (res), "=&d" (b)
+   : "d" (a), "1" (b), "d" (c)
+   : "A1"
+         );
+   return res;
+}
+
+#undef MULT16_32_Q14
+static inline spx_word32_t MULT16_32_Q14(spx_word16_t a, spx_word32_t b)
+{
+   spx_word32_t res;
+   __asm__
+         (
+         "%2 <<= 1;\n\t"
+         "A1 = %1.L*%2.L (M);\n\t"
+         "A1 = A1 >>> 15;\n\t"
+         "%0 = (A1 += %1.L*%2.H);\n\t"
+   : "=W" (res), "=d" (a), "=d" (b)
+   : "1" (a), "2" (b)
+   : "A1"
+         );
+   return res;
+}
+
+#undef MAC16_32_Q14
+static inline spx_word32_t MAC16_32_Q14(spx_word32_t c, spx_word16_t a, spx_word32_t b)
+{
+   spx_word32_t res;
+   __asm__
+         (
+         "%1 <<= 1;\n\t"
+         "A1 = %2.L*%1.L (M);\n\t"
+         "A1 = A1 >>> 15;\n\t"
+         "%0 = (A1 += %2.L*%1.H);\n\t"
+         "%0 = %0 + %4;\n\t"
+   : "=&W" (res), "=&d" (b)
+   : "d" (a), "1" (b), "d" (c)
+   : "A1"
+         );
+   return res;
+}
+
+#endif
diff --git a/3rdparty/speex/libspeex/fixed_debug.h b/3rdparty/speex/libspeex/fixed_debug.h
new file mode 100644
index 0000000..d5c449f
--- /dev/null
+++ b/3rdparty/speex/libspeex/fixed_debug.h
@@ -0,0 +1,487 @@
+/* Copyright (C) 2003 Jean-Marc Valin */
+/**
+   @file fixed_debug.h
+   @brief Fixed-point operations with debugging
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FIXED_DEBUG_H
+#define FIXED_DEBUG_H
+
+#include <stdio.h>
+
+extern long long spx_mips;
+#define MIPS_INC spx_mips++,
+
+#define QCONST16(x,bits) ((spx_word16_t)(.5+(x)*(((spx_word32_t)1)<<(bits))))
+#define QCONST32(x,bits) ((spx_word32_t)(.5+(x)*(((spx_word32_t)1)<<(bits))))
+
+
+#define VERIFY_SHORT(x) ((x)<=32767&&(x)>=-32768)
+#define VERIFY_INT(x) ((x)<=2147483647LL&&(x)>=-2147483648LL)
+
+static inline short NEG16(int x)
+{
+   int res;
+   if (!VERIFY_SHORT(x))
+   {
+      fprintf (stderr, "NEG16: input is not short: %d\n", (int)x);
+   }
+   res = -x;
+   if (!VERIFY_SHORT(res))
+      fprintf (stderr, "NEG16: output is not short: %d\n", (int)res);
+   spx_mips++;
+   return res;
+}
+static inline int NEG32(long long x)
+{
+   long long res;
+   if (!VERIFY_INT(x))
+   {
+      fprintf (stderr, "NEG16: input is not int: %d\n", (int)x);
+   }
+   res = -x;
+   if (!VERIFY_INT(res))
+      fprintf (stderr, "NEG16: output is not int: %d\n", (int)res);
+   spx_mips++;
+   return res;
+}
+
+#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 in %s: line %d\n", x, file, line);
+   }
+   res = x;
+   spx_mips++;
+   return res;
+}
+
+#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, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line);
+   }
+   res = x;
+   spx_mips++;
+   return res;
+}
+
+#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 in %s: line %d\n", a, shift, file, line);
+   }
+   res = a>>shift;
+   if (!VERIFY_SHORT(res))
+      fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line);
+   spx_mips++;
+   return res;
+}
+#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, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line);
+   }
+   res = a<<shift;
+   if (!VERIFY_SHORT(res))
+      fprintf (stderr, "SHL16: output is not short: %d in %s: line %d\n", res, file, line);
+   spx_mips++;
+   return res;
+}
+
+static inline int SHR32(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);
+   }
+   res = a>>shift;
+   if (!VERIFY_INT(res))
+   {
+      fprintf (stderr, "SHR32: output is not int: %d\n", (int)res);
+   }
+   spx_mips++;
+   return res;
+}
+static inline int SHL32(long long a, int shift) 
+{
+   long long  res;
+   if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
+   {
+      fprintf (stderr, "SHL32: inputs are not int: %d %d\n", (int)a, shift);
+   }
+   res = a<<shift;
+   if (!VERIFY_INT(res))
+   {
+      fprintf (stderr, "SHL32: output is not int: %d\n", (int)res);
+   }
+   spx_mips++;
+   return res;
+}
+
+#define PSHR16(a,shift) (SHR16(ADD16((a),((1<<((shift))>>1))),shift))
+#define PSHR32(a,shift) (SHR32(ADD32((a),((1<<((shift))>>1))),shift))
+#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
+
+#define 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 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 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 in %s: line %d\n", a,b,res, file, line);
+   }
+   spx_mips++;
+   return res;
+}
+
+#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 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 in %s: line %d\n", (int)res, file, line);
+   }
+   spx_mips++;
+   return res;
+}
+
+static inline int SUB32(long long a, long long b) 
+{
+   long long res;
+   if (!VERIFY_INT(a) || !VERIFY_INT(b))
+   {
+      fprintf (stderr, "SUB32: inputs are not int: %d %d\n", (int)a, (int)b);
+   }
+   res = a-b;
+   if (!VERIFY_INT(res))
+      fprintf (stderr, "SUB32: output is not int: %d\n", (int)res);
+   spx_mips++;
+   return res;
+}
+
+#define ADD64(a,b) (MIPS_INC(a)+(b))
+
+/* result fits in 16 bits */
+static inline short MULT16_16_16(int a, int b) 
+{
+   int res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "MULT16_16_16: inputs are not short: %d %d\n", a, b);
+   }
+   res = a*b;
+   if (!VERIFY_SHORT(res))
+      fprintf (stderr, "MULT16_16_16: output is not short: %d\n", res);
+   spx_mips++;
+   return res;
+}
+
+#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 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 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)     (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))))
+
+
+#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 in %s: line %d\n", Q, (int)a, (int)b, file, line);
+   }
+   if (ABS32(b)>=(1<<(15+Q)))
+      fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);      
+   res = (((long long)a)*(long long)b) >> Q;
+   if (!VERIFY_INT(res))
+      fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line);
+   spx_mips+=5;
+   return res;
+}
+
+static inline int MULT16_32_PX(int a, long long b, int Q)
+{
+   long long res;
+   if (!VERIFY_SHORT(a) || !VERIFY_INT(b))
+   {
+      fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d\n", Q, (int)a, (int)b);
+   }
+   if (ABS32(b)>=(1<<(15+Q)))
+      fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b);      
+   res = ((((long long)a)*(long long)b) + ((1<<Q)>>1))>> Q;
+   if (!VERIFY_INT(res))
+      fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d\n", Q, (int)a, (int)b,(int)res);
+   spx_mips+=5;
+   return res;
+}
+
+
+#define MULT16_32_Q11(a,b) MULT16_32_QX(a,b,11)
+#define MAC16_32_Q11(c,a,b) ADD32((c),MULT16_32_Q11((a),(b)))
+#define MULT16_32_Q12(a,b) MULT16_32_QX(a,b,12)
+#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)
+{
+   if (a>b)
+      a=b;
+   if (a<-b)
+      a = -b;
+   return a;
+}
+
+static inline int MULT16_16_Q11_32(int a, int b) 
+{
+   long long res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "MULT16_16_Q11: inputs are not short: %d %d\n", a, b);
+   }
+   res = ((long long)a)*b;
+   res >>= 11;
+   if (!VERIFY_INT(res))
+      fprintf (stderr, "MULT16_16_Q11: output is not short: %d*%d=%d\n", (int)a, (int)b, (int)res);
+   spx_mips+=3;
+   return res;
+}
+static inline short MULT16_16_Q13(int a, int b) 
+{
+   long long res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "MULT16_16_Q13: inputs are not short: %d %d\n", a, b);
+   }
+   res = ((long long)a)*b;
+   res >>= 13;
+   if (!VERIFY_SHORT(res))
+      fprintf (stderr, "MULT16_16_Q13: output is not short: %d*%d=%d\n", a, b, (int)res);
+   spx_mips+=3;
+   return res;
+}
+static inline short MULT16_16_Q14(int a, int b) 
+{
+   long long res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "MULT16_16_Q14: inputs are not short: %d %d\n", a, b);
+   }
+   res = ((long long)a)*b;
+   res >>= 14;
+   if (!VERIFY_SHORT(res))
+      fprintf (stderr, "MULT16_16_Q14: output is not short: %d\n", (int)res);
+   spx_mips+=3;
+   return res;
+}
+static inline short MULT16_16_Q15(int a, int b) 
+{
+   long long res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "MULT16_16_Q15: inputs are not short: %d %d\n", a, 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;
+}
+
+static inline short MULT16_16_P13(int a, int b) 
+{
+   long long res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "MULT16_16_P13: inputs are not short: %d %d\n", a, b);
+   }
+   res = ((long long)a)*b;
+   res += 4096;
+   if (!VERIFY_INT(res))
+      fprintf (stderr, "MULT16_16_P13: overflow: %d*%d=%d\n", a, b, (int)res);
+   res >>= 13;
+   if (!VERIFY_SHORT(res))
+      fprintf (stderr, "MULT16_16_P13: output is not short: %d*%d=%d\n", a, b, (int)res);
+   spx_mips+=4;
+   return res;
+}
+static inline short MULT16_16_P14(int a, int b) 
+{
+   long long res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "MULT16_16_P14: inputs are not short: %d %d\n", a, b);
+   }
+   res = ((long long)a)*b;
+   res += 8192;
+   if (!VERIFY_INT(res))
+      fprintf (stderr, "MULT16_16_P14: overflow: %d*%d=%d\n", a, b, (int)res);
+   res >>= 14;
+   if (!VERIFY_SHORT(res))
+      fprintf (stderr, "MULT16_16_P14: output is not short: %d*%d=%d\n", a, b, (int)res);
+   spx_mips+=4;
+   return res;
+}
+static inline short MULT16_16_P15(int a, int b) 
+{
+   long long res;
+   if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+   {
+      fprintf (stderr, "MULT16_16_P15: inputs are not short: %d %d\n", a, b);
+   }
+   res = ((long long)a)*b;
+   res += 16384;
+   if (!VERIFY_INT(res))
+      fprintf (stderr, "MULT16_16_P15: overflow: %d*%d=%d\n", a, b, (int)res);
+   res >>= 15;
+   if (!VERIFY_SHORT(res))
+      fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res);
+   spx_mips+=4;
+   return res;
+}
+
+#define DIV32_16(a, b) _DIV32_16(a, b, __FILE__, __LINE__)
+
+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 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 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 in %s: line %d\n", (int)a,(int)b,(int)res, file, line);
+      if (res>32767)
+         res = 32767;
+      if (res<-32768)
+         res = -32768;
+   }
+   spx_mips+=20;
+   return res;
+}
+
+#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 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 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 in %s: line %d\n", (int)res, file, line);
+   spx_mips+=36;
+   return res;
+}
+#define PDIV32(a,b) DIV32(ADD32((a),(b)>>1),b)
+#define PDIV32_16(a,b) DIV32_16(ADD32((a),(b)>>1),b)
+
+#endif
diff --git a/3rdparty/speex/libspeex/fixed_generic.h b/3rdparty/speex/libspeex/fixed_generic.h
new file mode 100644
index 0000000..2948177
--- /dev/null
+++ b/3rdparty/speex/libspeex/fixed_generic.h
@@ -0,0 +1,106 @@
+/* Copyright (C) 2003 Jean-Marc Valin */
+/**
+   @file fixed_generic.h
+   @brief Generic fixed-point operations
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FIXED_GENERIC_H
+#define FIXED_GENERIC_H
+
+#define QCONST16(x,bits) ((spx_word16_t)(.5+(x)*(((spx_word32_t)1)<<(bits))))
+#define QCONST32(x,bits) ((spx_word32_t)(.5+(x)*(((spx_word32_t)1)<<(bits))))
+
+#define NEG16(x) (-(x))
+#define NEG32(x) (-(x))
+#define EXTRACT16(x) ((spx_word16_t)(x))
+#define EXTEND32(x) ((spx_word32_t)(x))
+#define SHR16(a,shift) ((a) >> (shift))
+#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 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 SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
+
+
+#define ADD16(a,b) ((spx_word16_t)((spx_word16_t)(a)+(spx_word16_t)(b)))
+#define SUB16(a,b) ((spx_word16_t)(a)-(spx_word16_t)(b))
+#define ADD32(a,b) ((spx_word32_t)(a)+(spx_word32_t)(b))
+#define SUB32(a,b) ((spx_word32_t)(a)-(spx_word32_t)(b))
+
+
+/* result fits in 16 bits */
+#define MULT16_16_16(a,b)     ((((spx_word16_t)(a))*((spx_word16_t)(b))))
+
+/* (spx_word32_t)(spx_word16_t) gives TI compiler a hint that it's 16x16->32 multiply */
+#define MULT16_16(a,b)     (((spx_word32_t)(spx_word16_t)(a))*((spx_word32_t)(spx_word16_t)(b)))
+
+#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b))))
+#define MULT16_32_Q12(a,b) ADD32(MULT16_16((a),SHR((b),12)), SHR(MULT16_16((a),((b)&0x00000fff)),12))
+#define MULT16_32_Q13(a,b) ADD32(MULT16_16((a),SHR((b),13)), SHR(MULT16_16((a),((b)&0x00001fff)),13))
+#define MULT16_32_Q14(a,b) ADD32(MULT16_16((a),SHR((b),14)), SHR(MULT16_16((a),((b)&0x00003fff)),14))
+
+#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)))
+
+
+#define MAC16_16_Q11(c,a,b)     (ADD32((c),SHR(MULT16_16((a),(b)),11)))
+#define MAC16_16_Q13(c,a,b)     (ADD32((c),SHR(MULT16_16((a),(b)),13)))
+#define MAC16_16_P13(c,a,b)     (ADD32((c),SHR(ADD32(4096,MULT16_16((a),(b))),13)))
+
+#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11))
+#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13))
+#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14))
+#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15))
+
+#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13))
+#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14))
+#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15))
+
+#define MUL_16_32_R15(a,bh,bl) ADD32(MULT16_16((a),(bh)), SHR(MULT16_16((a),(bl)),15))
+
+#define DIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a))/((spx_word16_t)(b))))
+#define PDIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word16_t)(b))))
+#define DIV32(a,b) (((spx_word32_t)(a))/((spx_word32_t)(b)))
+#define PDIV32(a,b) (((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word32_t)(b)))
+
+#endif
diff --git a/3rdparty/speex/libspeex/gain_table.c b/3rdparty/speex/libspeex/gain_table.c
new file mode 100644
index 0000000..00b8244
--- /dev/null
+++ b/3rdparty/speex/libspeex/gain_table.c
@@ -0,0 +1,160 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: gain_table.c
+   Codebook for 3-tap pitch prediction gain (128 entries)
+  
+   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.
+*/
+
+const signed char gain_cdbk_nb[512] = {
+-32, -32, -32, 0,
+-28, -67, -5, 33,
+-42, -6, -32, 18,
+-57, -10, -54, 35,
+-16, 27, -41, 42,
+19, -19, -40, 36,
+-45, 24, -21, 40,
+-8, -14, -18, 28,
+1, 14, -58, 53,
+-18, -88, -39, 39,
+-38, 21, -18, 37,
+-19, 20, -43, 38,
+10, 17, -48, 54,
+-52, -58, -13, 33,
+-44, -1, -11, 32,
+-12, -11, -34, 22,
+14, 0, -46, 46,
+-37, -35, -34, 5,
+-25, 44, -30, 43,
+6, -4, -63, 49,
+-31, 43, -41, 43,
+-23, 30, -43, 41,
+-43, 26, -14, 44,
+-33, 1, -13, 27,
+-13, 18, -37, 37,
+-46, -73, -45, 34,
+-36, 24, -25, 34,
+-36, -11, -20, 19,
+-25, 12, -18, 33,
+-36, -69, -59, 34,
+-45, 6, 8, 46,
+-22, -14, -24, 18,
+-1, 13, -44, 44,
+-39, -48, -26, 15,
+-32, 31, -37, 34,
+-33, 15, -46, 31,
+-24, 30, -36, 37,
+-41, 31, -23, 41,
+-50, 22, -4, 50,
+-22, 2, -21, 28,
+-17, 30, -34, 40,
+-7, -60, -28, 29,
+-38, 42, -28, 42,
+-44, -11, 21, 43,
+-16, 8, -44, 34,
+-39, -55, -43, 21,
+-11, -35, 26, 41,
+-9, 0, -34, 29,
+-8, 121, -81, 113,
+7, -16, -22, 33,
+-37, 33, -31, 36,
+-27, -7, -36, 17,
+-34, 70, -57, 65,
+-37, -11, -48, 21,
+-40, 17, -1, 44,
+-33, 6, -6, 33,
+-9, 0, -20, 34,
+-21, 69, -33, 57,
+-29, 33, -31, 35,
+-55, 12, -1, 49,
+-33, 27, -22, 35,
+-50, -33, -47, 17,
+-50, 54, 51, 94,
+-1, -5, -44, 35,
+-4, 22, -40, 45,
+-39, -66, -25, 24,
+-33, 1, -26, 20,
+-24, -23, -25, 12,
+-11, 21, -45, 44,
+-25, -45, -19, 17,
+-43, 105, -16, 82,
+5, -21, 1, 41,
+-16, 11, -33, 30,
+-13, -99, -4, 57,
+-37, 33, -15, 44,
+-25, 37, -63, 54,
+-36, 24, -31, 31,
+-53, -56, -38, 26,
+-41, -4, 4, 37,
+-33, 13, -30, 24,
+49, 52, -94, 114,
+-5, -30, -15, 23,
+1, 38, -40, 56,
+-23, 12, -36, 29,
+-17, 40, -47, 51,
+-37, -41, -39, 11,
+-49, 34, 0, 58,
+-18, -7, -4, 34,
+-16, 17, -27, 35,
+30, 5, -62, 65,
+4, 48, -68, 76,
+-43, 11, -11, 38,
+-18, 19, -15, 41,
+-23, -62, -39, 23,
+-42, 10, -2, 41,
+-21, -13, -13, 25,
+-9, 13, -47, 42,
+-23, -62, -24, 24,
+-44, 60, -21, 58,
+-18, -3, -52, 32,
+-22, 22, -36, 34,
+-75, 57, 16, 90,
+-19, 3, 10, 45,
+-29, 23, -38, 32,
+-5, -62, -51, 38,
+-51, 40, -18, 53,
+-42, 13, -24, 32,
+-34, 14, -20, 30,
+-56, -75, -26, 37,
+-26, 32, 15, 59,
+-26, 17, -29, 29,
+-7, 28, -52, 53,
+-12, -30, 5, 30,
+-5, -48, -5, 35,
+2, 2, -43, 40,
+21, 16, 16, 75,
+-25, -45, -32, 10,
+-43, 18, -10, 42,
+9, 0, -1, 52,
+-1, 7, -30, 36,
+19, -48, -4, 48,
+-28, 25, -29, 32,
+-22, 0, -31, 22,
+-32, 17, -10, 36,
+-64, -41, -62, 36,
+-52, 15, 16, 58,
+-30, -22, -32, 6,
+-7, 9, -38, 36};
diff --git a/3rdparty/speex/libspeex/gain_table_lbr.c b/3rdparty/speex/libspeex/gain_table_lbr.c
new file mode 100644
index 0000000..3c1c3db
--- /dev/null
+++ b/3rdparty/speex/libspeex/gain_table_lbr.c
@@ -0,0 +1,64 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: gain_table_lbr.c
+   Codebook for 3-tap pitch prediction gain (32 entries)
+  
+   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.
+*/
+
+const signed char gain_cdbk_lbr[128] = {
+-32, -32, -32, 0,
+-31, -58, -16, 22,
+-41, -24, -43, 14,
+-56, -22, -55, 29,
+-13, 33, -41, 47,
+-4, -39, -9, 29,
+-41, 15, -12, 38,
+-8, -15, -12, 31,
+1, 2, -44, 40,
+-22, -66, -42, 27,
+-38, 28, -23, 38,
+-21, 14, -37, 31,
+0, 21, -50, 52,
+-53, -71, -27, 33,
+-37, -1, -19, 25,
+-19, -5, -28, 22,
+6, 65, -44, 74,
+-33, -48, -33, 9,
+-40, 57, -14, 58,
+-17, 4, -45, 32,
+-31, 38, -33, 36,
+-23, 28, -40, 39,
+-43, 29, -12, 46,
+-34, 13, -23, 28,
+-16, 15, -27, 34,
+-14, -82, -15, 43,
+-31, 25, -32, 29,
+-21, 5, -5, 38,
+-47, -63, -51, 33,
+-46, 12, 3, 47,
+-28, -17, -29, 11,
+-10, 14, -40, 38};
diff --git a/3rdparty/speex/libspeex/hexc_10_32_table.c b/3rdparty/speex/libspeex/hexc_10_32_table.c
new file mode 100644
index 0000000..8dd408f
--- /dev/null
+++ b/3rdparty/speex/libspeex/hexc_10_32_table.c
@@ -0,0 +1,66 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: hexc_10_32_table.c
+   Codebook for high-band excitation in SB-CELP mode (4000 bps)
+
+   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.
+*/
+
+const signed char hexc_10_32_table[320] = {
+-3, -2, -1, 0, -4, 5, 35, -40, -9, 13, 
+-44, 5, -27, -1, -7, 6, -11, 7, -8, 7, 
+19, -14, 15, -4, 9, -10, 10, -8, 10, -9, 
+-1, 1, 0, 0, 2, 5, -18, 22, -53, 50, 
+1, -23, 50, -36, 15, 3, -13, 14, -10, 6, 
+1, 5, -3, 4, -2, 5, -32, 25, 5, -2, 
+-1, -4, 1, 11, -29, 26, -6, -15, 30, -18, 
+0, 15, -17, 40, -41, 3, 9, -2, -2, 3, 
+-3, -1, -5, 2, 21, -6, -16, -21, 23, 2, 
+60, 15, 16, -16, -9, 14, 9, -1, 7, -9, 
+0, 1, 1, 0, -1, -6, 17, -28, 54, -45, 
+-1, 1, -1, -6, -6, 2, 11, 26, -29, -2, 
+46, -21, 34, 12, -23, 32, -23, 16, -10, 3, 
+66, 19, -20, 24, 7, 11, -3, 0, -3, -1, 
+-50, -46, 2, -18, -3, 4, -1, -2, 3, -3, 
+-19, 41, -36, 9, 11, -24, 21, -16, 9, -3, 
+-25, -3, 10, 18, -9, -2, -5, -1, -5, 6, 
+-4, -3, 2, -26, 21, -19, 35, -15, 7, -13, 
+17, -19, 39, -43, 48, -31, 16, -9, 7, -2, 
+-5, 3, -4, 9, -19, 27, -55, 63, -35, 10, 
+26, -44, -2, 9, 4, 1, -6, 8, -9, 5, 
+-8, -1, -3, -16, 45, -42, 5, 15, -16, 10, 
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+-16, 24, -55, 47, -38, 27, -19, 7, -3, 1, 
+16, 27, 20, -19, 18, 5, -7, 1, -5, 2, 
+-6, 8, -22, 0, -3, -3, 8, -1, 7, -8, 
+1, -3, 5, 0, 17, -48, 58, -52, 29, -7, 
+-2, 3, -10, 6, -26, 58, -31, 1, -6, 3, 
+93, -29, 39, 3, 17, 5, 6, -1, -1, -1, 
+27, 13, 10, 19, -7, -34, 12, 10, -4, 9, 
+-76, 9, 8, -28, -2, -11, 2, -1, 3, 1, 
+-83, 38, -39, 4, -16, -6, -2, -5, 5, -2, 
+};
diff --git a/3rdparty/speex/libspeex/hexc_table.c b/3rdparty/speex/libspeex/hexc_table.c
new file mode 100644
index 0000000..268408a
--- /dev/null
+++ b/3rdparty/speex/libspeex/hexc_table.c
@@ -0,0 +1,162 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: hexc_table.c
+   Codebook for high-band excitation in SB-CELP mode (8000 bps with sign)
+
+   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.
+*/
+
+const signed char hexc_table[1024] = {
+-24, 21, -20, 5, -5, -7, 14, -10, 
+2, -27, 16, -20, 0, -32, 26, 19, 
+8, -11, -41, 31, 28, -27, -32, 34, 
+42, 34, -17, 22, -10, 13, -29, 18, 
+-12, -26, -24, 11, 22, 5, -5, -5, 
+54, -68, -43, 57, -25, 24, 4, 4, 
+26, -8, -12, -17, 54, 30, -45, 1, 
+10, -15, 18, -41, 11, 68, -67, 37, 
+-16, -24, -16, 38, -22, 6, -29, 30, 
+66, -27, 5, 7, -16, 13, 2, -12, 
+-7, -3, -20, 36, 4, -28, 9, 3, 
+32, 48, 26, 39, 3, 0, 7, -21, 
+-13, 5, -82, -7, 73, -20, 34, -9, 
+-5, 1, -1, 10, -5, -10, -1, 9, 
+1, -9, 10, 0, -14, 11, -1, -2, 
+-1, 11, 20, 96, -81, -22, -12, -9, 
+-58, 9, 24, -30, 26, -35, 27, -12, 
+13, -18, 56, -59, 15, -7, 23, -15, 
+-1, 6, -25, 14, -22, -20, 47, -11, 
+16, 2, 38, -23, -19, -30, -9, 40, 
+-11, 5, 4, -6, 8, 26, -21, -11, 
+127, 4, 1, 6, -9, 2, -7, -2, 
+-3, 7, -5, 10, -19, 7, -106, 91, 
+-3, 9, -4, 21, -8, 26, -80, 8, 
+1, -2, -10, -17, -17, -27, 32, 71, 
+6, -29, 11, -23, 54, -38, 29, -22, 
+39, 87, -31, -12, -20, 3, -2, -2, 
+2, 20, 0, -1, -35, 27, 9, -6, 
+-12, 3, -12, -6, 13, 1, 14, -22, 
+-59, -15, -17, -25, 13, -7, 7, 3, 
+0, 1, -7, 6, -3, 61, -37, -23, 
+-23, -29, 38, -31, 27, 1, -8, 2, 
+-27, 23, -26, 36, -34, 5, 24, -24, 
+-6, 7, 3, -59, 78, -62, 44, -16, 
+1, 6, 0, 17, 8, 45, 0, -110, 
+6, 14, -2, 32, -77, -56, 62, -3, 
+3, -13, 4, -16, 102, -15, -36, -1, 
+9, -113, 6, 23, 0, 9, 9, 5, 
+-8, -1, -14, 5, -12, 121, -53, -27, 
+-8, -9, 22, -13, 3, 2, -3, 1, 
+-2, -71, 95, 38, -19, 15, -16, -5, 
+71, 10, 2, -32, -13, -5, 15, -1, 
+-2, -14, -85, 30, 29, 6, 3, 2, 
+0, 0, 0, 0, 0, 0, 0, 0, 
+2, -65, -56, -9, 18, 18, 23, -14, 
+-2, 0, 12, -29, 26, -12, 1, 2, 
+-12, -64, 90, -6, 4, 1, 5, -5, 
+-110, -3, -31, 22, -29, 9, 0, 8, 
+-40, -5, 21, -5, -5, 13, 10, -18, 
+40, 1, 35, -20, 30, -28, 11, -6, 
+19, 7, 14, 18, -64, 9, -6, 16, 
+51, 68, 8, 16, 12, -8, 0, -9, 
+20, -22, 25, 7, -4, -13, 41, -35, 
+93, -18, -54, 11, -1, 1, -9, 4, 
+-66, 66, -31, 20, -22, 25, -23, 11, 
+10, 9, 19, 15, 11, -5, -31, -10, 
+-23, -28, -6, -6, -3, -4, 5, 3, 
+-28, 22, -11, -42, 25, -25, -16, 41, 
+34, 47, -6, 2, 42, -19, -22, 5, 
+-39, 32, 6, -35, 22, 17, -30, 8, 
+-26, -11, -11, 3, -12, 33, 33, -37, 
+21, -1, 6, -4, 3, 0, -5, 5, 
+12, -12, 57, 27, -61, -3, 20, -17, 
+2, 0, 4, 0, -2, -33, -58, 81, 
+-23, 39, -10, -5, 2, 6, -7, 5, 
+4, -3, -2, -13, -23, -72, 107, 15, 
+-5, 0, -7, -3, -6, 5, -4, 15, 
+47, 12, -31, 25, -16, 8, 22, -25, 
+-62, -56, -18, 14, 28, 12, 2, -11, 
+74, -66, 41, -20, -7, 16, -20, 16, 
+-8, 0, -16, 4, -19, 92, 12, -59, 
+-14, -39, 49, -25, -16, 23, -27, 19, 
+-3, -33, 19, 85, -29, 6, -7, -10, 
+16, -7, -12, 1, -6, 2, 4, -2, 
+64, 10, -25, 41, -2, -31, 15, 0, 
+110, 50, 69, 35, 28, 19, -10, 2, 
+-43, -49, -56, -15, -16, 10, 3, 12, 
+-1, -8, 1, 26, -12, -1, 7, -11, 
+-27, 41, 25, 1, -11, -18, 22, -7, 
+-1, -47, -8, 23, -3, -17, -7, 18, 
+-125, 59, -5, 3, 18, 1, 2, 3, 
+27, -35, 65, -53, 50, -46, 37, -21, 
+-28, 7, 14, -37, -5, -5, 12, 5, 
+-8, 78, -19, 21, -6, -16, 8, -7, 
+5, 2, 7, 2, 10, -6, 12, -60, 
+44, 11, -36, -32, 31, 0, 2, -2, 
+2, 1, -3, 7, -10, 17, -21, 10, 
+6, -2, 19, -2, 59, -38, -86, 38, 
+8, -41, -30, -45, -33, 7, 15, 28, 
+29, -7, 24, -40, 7, 7, 5, -2, 
+9, 24, -23, -18, 6, -29, 30, 2, 
+28, 49, -11, -46, 10, 43, -13, -9, 
+-1, -3, -7, -7, -17, -6, 97, -33, 
+-21, 3, 5, 1, 12, -43, -8, 28, 
+7, -43, -7, 17, -20, 19, -1, 2, 
+-13, 9, 54, 34, 9, -28, -11, -9, 
+-17, 110, -59, 44, -26, 0, 3, -12, 
+-47, 73, -34, -43, 38, -33, 16, -5, 
+-46, -4, -6, -2, -25, 19, -29, 28, 
+-13, 5, 14, 27, -40, -43, 4, 32, 
+-13, -2, -35, -4, 112, -42, 9, -12, 
+37, -28, 17, 14, -19, 35, -39, 23, 
+3, -14, -1, -57, -5, 94, -9, 3, 
+-39, 5, 30, -10, -32, 42, -13, -14, 
+-97, -63, 30, -9, 1, -7, 12, 5, 
+20, 17, -9, -36, -30, 25, 47, -9, 
+-15, 12, -22, 98, -8, -50, 15, -27, 
+21, -16, -11, 2, 12, -10, 10, -3, 
+33, 36, -96, 0, -17, 31, -9, 9, 
+3, -20, 13, -11, 8, -4, 10, -10, 
+9, 1, 112, -70, -27, 5, -21, 2, 
+-57, -3, -29, 10, 19, -21, 21, -10, 
+-66, -3, 91, -35, 30, -12, 0, -7, 
+59, -28, 26, 2, 14, -18, 1, 1, 
+11, 17, 20, -54, -59, 27, 4, 29, 
+32, 5, 19, 12, -4, 1, 7, -10, 
+5, -2, 10, 0, 23, -5, 28, -104, 
+46, 11, 16, 3, 29, 1, -8, -14, 
+1, 7, -50, 88, -62, 26, 8, -17, 
+-14, 50, 0, 32, -12, -3, -27, 18, 
+-8, -5, 8, 3, -20, -11, 37, -12, 
+9, 33, 46, -101, -1, -4, 1, 6, 
+-1, 28, -42, -15, 16, 5, -1, -2, 
+-55, 85, 38, -9, -4, 11, -2, -9, 
+-6, 3, -20, -10, -77, 89, 24, -3, 
+-104, -57, -26, -31, -20, -6, -9, 14, 
+20, -23, 46, -15, -31, 28, 1, -15, 
+-2, 6, -2, 31, 45, -76, 23, -25, 
+};
diff --git a/3rdparty/speex/libspeex/high_lsp_tables.c b/3rdparty/speex/libspeex/high_lsp_tables.c
new file mode 100644
index 0000000..e82e875
--- /dev/null
+++ b/3rdparty/speex/libspeex/high_lsp_tables.c
@@ -0,0 +1,163 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: high_lsp_tables.c
+   Codebooks for high-band LSPs in SB-CELP mode
+  
+   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.
+*/
+ 
+const signed char high_lsp_cdbk[512]={
+39,12,-14,-20,-29,-61,-67,-76,
+-32,-71,-67,68,77,46,34,5,
+-13,-48,-46,-72,-81,-84,-60,-58,
+-40,-28,82,93,68,45,29,3,
+-19,-47,-28,-43,-35,-30,-8,-13,
+-39,-91,-91,-123,-96,10,10,-6,
+-18,-55,-60,-91,-56,-36,-27,-16,
+-48,-75,40,28,-10,-28,35,9,
+37,19,1,-20,-31,-41,-18,-25,
+-35,-68,-80,45,27,-1,47,13,
+0,-29,-35,-57,-50,-79,-73,-38,
+-19,5,35,14,-10,-23,16,-8,
+5,-24,-40,-62,-23,-27,-22,-16,
+-18,-46,-72,-77,43,21,33,1,
+-80,-70,-70,-64,-56,-52,-39,-33,
+-31,-38,-19,-19,-15,32,33,-2,
+7,-15,-15,-24,-23,-33,-41,-56,
+-24,-57,5,89,64,41,27,5,
+-9,-47,-60,-97,-97,-124,-20,-9,
+-44,-73,31,29,-4,64,48,7,
+-35,-57,0,-3,-26,-47,-3,-6,
+-40,-76,-79,-48,12,81,55,10,
+9,-24,-43,-73,-57,-69,16,5,
+-28,-53,18,29,20,0,-4,-11,
+6,-13,23,7,-17,-35,-37,-37,
+-30,-68,-63,6,24,-9,-14,3,
+21,-13,-27,-57,-49,-80,-24,-41,
+-5,-16,-5,1,45,25,12,-7,
+3,-15,-6,-16,-15,-8,6,-13,
+-42,-81,-80,-87,14,1,-10,-3,
+-43,-69,-46,-24,-28,-29,36,6,
+-43,-56,-12,12,54,79,43,9,
+54,22,2,8,-12,-43,-46,-52,
+-38,-69,-89,-5,75,38,33,5,
+-13,-53,-62,-87,-89,-113,-99,-55,
+-34,-37,62,55,33,16,21,-2,
+-17,-46,-29,-38,-38,-48,-39,-42,
+-36,-75,-72,-88,-48,-30,21,2,
+-15,-57,-64,-98,-84,-76,25,1,
+-46,-80,-12,18,-7,3,34,6,
+38,31,23,4,-1,20,14,-15,
+-43,-78,-91,-24,14,-3,54,16,
+0,-27,-28,-44,-56,-83,-92,-89,
+-3,34,56,41,36,22,20,-8,
+-7,-35,-42,-62,-49,3,12,-10,
+-50,-87,-96,-66,92,70,38,9,
+-70,-71,-62,-42,-39,-43,-11,-7,
+-50,-79,-58,-50,-31,32,31,-6,
+-4,-25,7,-17,-38,-70,-58,-27,
+-43,-83,-28,59,36,20,31,2,
+-27,-71,-80,-109,-98,-75,-33,-32,
+-31,-2,33,15,-6,43,33,-5,
+0,-22,-10,-27,-34,-49,-11,-20,
+-41,-91,-100,-121,-39,57,41,10,
+-19,-50,-38,-59,-60,-70,-18,-20,
+-8,-31,-8,-15,1,-14,-26,-25,
+33,21,32,17,1,-19,-19,-26,
+-58,-81,-35,-22,45,30,11,-11,
+3,-26,-48,-87,-67,-83,-58,3,
+-1,-26,-20,44,10,25,39,5,
+-9,-35,-27,-38,7,10,4,-9,
+-42,-85,-102,-127,52,44,28,10,
+-47,-61,-40,-39,-17,-1,-10,-33,
+-42,-74,-48,21,-4,70,52,10};
+
+
+const signed char high_lsp_cdbk2[512]={
+-36,-62,6,-9,-10,-14,-56,23,
+1,-26,23,-48,-17,12,8,-7,
+23,29,-36,-28,-6,-29,-17,-5,
+40,23,10,10,-46,-13,36,6,
+4,-30,-29,62,32,-32,-1,22,
+-14,1,-4,-22,-45,2,54,4,
+-30,-57,-59,-12,27,-3,-31,8,
+-9,5,10,-14,32,66,19,9,
+2,-25,-37,23,-15,18,-38,-31,
+5,-9,-21,15,0,22,62,30,
+15,-12,-14,-46,77,21,33,3,
+34,29,-19,50,2,11,9,-38,
+-12,-37,62,1,-15,54,32,6,
+2,-24,20,35,-21,2,19,24,
+-13,55,4,9,39,-19,30,-1,
+-21,73,54,33,8,18,3,15,
+6,-19,-47,6,-3,-48,-50,1,
+26,20,8,-23,-50,65,-14,-55,
+-17,-31,-37,-28,53,-1,-17,-53,
+1,57,11,-8,-25,-30,-37,64,
+5,-52,-45,15,23,31,15,14,
+-25,24,33,-2,-44,-56,-18,6,
+-21,-43,4,-12,17,-37,20,-10,
+34,15,2,15,55,21,-11,-31,
+-6,46,25,16,-9,-25,-8,-62,
+28,17,20,-32,-29,26,30,25,
+-19,2,-16,-17,26,-51,2,50,
+42,19,-66,23,29,-2,3,19,
+-19,-37,32,15,6,30,-34,13,
+11,-5,40,31,10,-42,4,-9,
+26,-9,-70,17,-2,-23,20,-22,
+-55,51,-24,-31,22,-22,15,-13,
+3,-10,-28,-16,56,4,-63,11,
+-18,-15,-18,-38,-35,16,-7,34,
+-1,-21,-49,-47,9,-37,7,8,
+69,55,20,6,-33,-45,-10,-9,
+6,-9,12,71,15,-3,-42,-7,
+-24,32,-35,-2,-42,-17,-5,0,
+-2,-33,-54,13,-12,-34,47,23,
+19,55,7,-8,74,31,14,16,
+-23,-26,19,12,-18,-49,-28,-31,
+-20,2,-14,-20,-47,78,40,13,
+-23,-11,21,-6,18,1,47,5,
+38,35,32,46,22,8,13,16,
+-14,18,51,19,40,39,11,-26,
+-1,-17,47,2,-53,-15,31,-22,
+38,21,-15,-16,5,-33,53,15,
+-38,86,11,-3,-24,49,13,-4,
+-11,-18,28,20,-12,-27,-26,35,
+-25,-35,-3,-20,-61,30,10,-55,
+-12,-22,-52,-54,-14,19,-32,-12,
+45,15,-8,-48,-9,11,-32,8,
+-16,-34,-13,51,18,38,-2,-32,
+-17,22,-2,-18,-28,-70,59,27,
+-28,-19,-10,-20,-9,-9,-8,-21,
+21,-8,35,-2,45,-3,-9,12,
+0,30,7,-39,43,27,-38,-91,
+30,26,19,-55,-4,63,14,-17,
+13,9,13,2,7,4,6,61,
+72,-1,-17,29,-1,-22,-17,8,
+-28,-37,63,44,41,3,2,14,
+9,-6,75,-8,-7,-12,-15,-12,
+13,9,-4,30,-22,-65,15,0,
+-45,4,-4,1,5,22,11,23};
diff --git a/3rdparty/speex/libspeex/jitter.c b/3rdparty/speex/libspeex/jitter.c
new file mode 100644
index 0000000..2b64453
--- /dev/null
+++ b/3rdparty/speex/libspeex/jitter.c
@@ -0,0 +1,627 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: speex_jitter.h
+
+   Adaptive jitter buffer for Speex
+
+   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 "misc.h"
+#include <speex/speex.h>
+#include <speex/speex_bits.h>
+#include <speex/speex_jitter.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define LATE_BINS 15
+#define MAX_MARGIN 30                     /**< Number of bins in margin histogram */
+
+#define SPEEX_JITTER_MAX_BUFFER_SIZE 200   /**< Maximum number of packets in jitter buffer */
+
+
+
+#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) */
+
+   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           */
+
+   int tick_size;                                                         /**< Output granularity                  */
+   int reset_state;                                                       /**< True if state was just reset        */
+   int buffer_margin;                                                     /**< How many frames we want to keep in the buffer (lower bound) */
+   int late_cutoff;                                                       /**< How late must a packet be for it not to be considered at all */
+   int interp_requested;                                                  /**< An interpolation is requested by speex_jitter_update_delay() */
+
+   int lost_count;                                                        /**< Number of consecutive lost packets  */
+   float shortterm_margin[MAX_MARGIN];                                    /**< Short term margin histogram         */
+   float longterm_margin[MAX_MARGIN];                                     /**< Long term margin histogram          */
+   float loss_rate;                                                       /**< Average loss rate                   */
+};
+
+/** Initialise jitter buffer */
+JitterBuffer *jitter_buffer_init(int tick)
+{
+   JitterBuffer *jitter = (JitterBuffer*)speex_alloc(sizeof(JitterBuffer));
+   if (jitter)
+   {
+      int i;
+      for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
+         jitter->buf[i]=NULL;
+      jitter->tick_size = tick;
+      jitter->buffer_margin = 1;
+      jitter->late_cutoff = 50;
+      jitter_buffer_reset(jitter);
+   }
+   return jitter;
+}
+
+/** Reset jitter buffer */
+void jitter_buffer_reset(JitterBuffer *jitter)
+{
+   int i;
+   for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
+   {
+      if (jitter->buf[i])
+      {
+         speex_free(jitter->buf[i]);
+         jitter->buf[i] = NULL;
+      }
+   }
+   /* Timestamp is actually undefined at this point */
+   jitter->pointer_timestamp = 0;
+   jitter->current_timestamp = 0;
+   jitter->reset_state = 1;
+   jitter->lost_count = 0;
+   jitter->loss_rate = 0;
+   for (i=0;i<MAX_MARGIN;i++)
+   {
+      jitter->shortterm_margin[i] = 0;
+      jitter->longterm_margin[i] = 0;
+   }
+   /*fprintf (stderr, "reset\n");*/
+}
+
+/** Destroy jitter buffer */
+void jitter_buffer_destroy(JitterBuffer *jitter)
+{
+   jitter_buffer_reset(jitter);
+   speex_free(jitter);
+}
+
+/** Put one packet into the jitter buffer */
+void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
+{
+   int i,j;
+   spx_int32_t arrival_margin;
+   /*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;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
+   {
+      /* Make sure we don't discard a "just-late" packet in case we want to play it next (if we interpolate). */
+      if (jitter->buf[i] && LE32(jitter->timestamp[i] + jitter->span[i], jitter->pointer_timestamp))
+      {
+         /*fprintf (stderr, "cleaned (not played)\n");*/
+         speex_free(jitter->buf[i]);
+         jitter->buf[i] = NULL;
+      }
+   }
+
+   /*Find an empty slot in the buffer*/
+   for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
+   {
+      if (jitter->buf[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;j<SPEEX_JITTER_MAX_BUFFER_SIZE;j++)
+      {
+         if (!jitter->buf[i] || LT32(jitter->timestamp[j],earliest))
+         {
+            earliest = jitter->timestamp[j];
+            i=j;
+         }
+      }
+      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;j<packet->len;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.
+      The arrival margin is how much in advance (or late) the packet it */
+   arrival_margin = (((spx_int32_t)packet->timestamp) - ((spx_int32_t)jitter->current_timestamp))/jitter->tick_size - jitter->buffer_margin;
+   
+   if (arrival_margin >= -jitter->late_cutoff)
+   {
+      /* Here we compute the histogram based on the time of arrival of the packet.
+         This is based on a (first-order) recursive average. We keep both a short-term
+         histogram and a long-term histogram */
+      spx_int32_t int_margin;
+      /* First, apply the "damping" of the recursive average to all bins */
+      for (i=0;i<MAX_MARGIN;i++)
+      {
+         jitter->shortterm_margin[i] *= .98;
+         jitter->longterm_margin[i] *= .995;
+      }
+      /* What histogram bin the packet should be counted in */
+      int_margin = LATE_BINS + arrival_margin;
+      if (int_margin>MAX_MARGIN-1)
+         int_margin = MAX_MARGIN-1;
+      if (int_margin<0)
+         int_margin = 0;
+      /* Add the packet to the right bin */
+      jitter->shortterm_margin[int_margin] += .02;
+      jitter->longterm_margin[int_margin] += .005;
+   } else {
+      /* Packet has arrived *way* too late, we pretty much consider it lost and not take it into account in the histogram */
+      /*fprintf (stderr, "way too late = %d\n", arrival_margin);*/
+      if (jitter->lost_count>20)
+      {
+         jitter_buffer_reset(jitter);
+      }
+   }
+#if 0 /* Enable to check how much is being buffered */
+   if (rand()%1000==0)
+   {
+      int count = 0;
+      for (j=0;j<SPEEX_JITTER_MAX_BUFFER_SIZE;j++)
+      {
+         if (jitter->buf[j])
+            count++;
+      }
+      fprintf (stderr, "buffer_size = %d\n", count);
+   }
+#endif
+}
+
+/** Get one packet from the jitter buffer */
+int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset)
+{
+   int i;
+   unsigned int 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 incomplete = 0;
+   
+   if (jitter->interp_requested)
+   {
+      jitter->interp_requested = 0;
+      if (start_offset)
+         *start_offset = 0;
+      packet->timestamp = jitter->pointer_timestamp;
+      packet->span = jitter->tick_size;
+      jitter->pointer_timestamp += jitter->tick_size;
+      packet->len = 0;
+      return JITTER_BUFFER_MISSING;
+   }
+   if (LT32(jitter->current_timestamp+jitter->tick_size, jitter->pointer_timestamp))
+   {
+      jitter->current_timestamp = jitter->pointer_timestamp;
+      speex_warning("did you forget to call jitter_buffer_tick() by any chance?");
+   }
+   /*fprintf (stderr, "get packet %d %d\n", jitter->pointer_timestamp, jitter->current_timestamp);*/
+
+   /* FIXME: This should be only what remaining of the current tick */
+   chunk_size = jitter->tick_size;
+   
+   /* Compiling arrival statistics */
+   
+   late_ratio_short = 0;
+   late_ratio_long = 0;
+   /* Count the proportion of packets that are late */
+   for (i=0;i<LATE_BINS;i++)
+   {
+      late_ratio_short += jitter->shortterm_margin[i];
+      late_ratio_long += jitter->longterm_margin[i];
+   }
+   /* Count the proportion of packets that are just on time */
+   ontime_ratio_short = jitter->shortterm_margin[LATE_BINS];
+   ontime_ratio_long = jitter->longterm_margin[LATE_BINS];
+   early_ratio_short = early_ratio_long = 0;
+   /* Count the proportion of packets that are early */
+   for (i=LATE_BINS+1;i<MAX_MARGIN;i++)
+   {
+      early_ratio_short += jitter->shortterm_margin[i];
+      early_ratio_long += jitter->longterm_margin[i];
+   }
+   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);*/
+   }
+   
+   
+   /* Searching for the packet that fits best */
+   
+   /* Search the buffer for a packet with the right timestamp and spanning the whole current chunk */
+   for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
+   {
+      if (jitter->buf[i] && jitter->timestamp[i]==jitter->pointer_timestamp && GE32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp+chunk_size))
+         break;
+   }
+   
+   /* If no match, try for an "older" packet that still spans (fully) the current chunk */
+   if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
+   {
+      for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
+      {
+         if (jitter->buf[i] && LE32(jitter->timestamp[i], jitter->pointer_timestamp) && GE32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp+chunk_size))
+            break;
+      }
+   }
+   
+   /* If still no match, try for an "older" packet that spans part of the current chunk */
+   if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
+   {
+      for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
+      {
+         if (jitter->buf[i] && LE32(jitter->timestamp[i], jitter->pointer_timestamp) && GT32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp))
+            break;
+      }
+   }
+   
+   /* If still no match, try for earliest packet possible */
+   if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
+   {
+      int found = 0;
+      spx_uint32_t best_time=0;
+      int best_span=0;
+      int besti=0;
+      for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
+      {
+         /* check if packet starts within current chunk */
+         if (jitter->buf[i] && LT32(jitter->timestamp[i],jitter->pointer_timestamp+chunk_size) && GE32(jitter->timestamp[i],jitter->pointer_timestamp))
+         {
+            if (!found || LT32(jitter->timestamp[i],best_time) || (jitter->timestamp[i]==best_time && GT32(jitter->span[i],best_span)))
+            {
+               best_time = jitter->timestamp[i];
+               best_span = jitter->span[i];
+               besti = i;
+               found = 1;
+            }
+         }
+      }
+      if (found)
+      {
+         i=besti;
+         incomplete = 1;
+         /*fprintf (stderr, "incomplete: %d %d %d %d\n", jitter->timestamp[i], jitter->pointer_timestamp, chunk_size, jitter->span[i]);*/
+      }
+   }
+
+   /* If we find something */
+   if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE)
+   {
+      /* 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];
+      /* Copy packet */
+      for (j=0;j<packet->len;j++)
+         packet->data[j] = jitter->buf[i][j];
+      /* Remove packet */
+      speex_free(jitter->buf[i]);
+      jitter->buf[i] = NULL;
+      /* Set timestamp and span (if requested) */
+      if (start_offset)
+         *start_offset = (spx_int32_t)jitter->timestamp[i]-(spx_int32_t)jitter->pointer_timestamp;
+      packet->timestamp = jitter->timestamp[i];
+      packet->span = jitter->span[i];
+      /* Point at the end of the current packet */
+      jitter->pointer_timestamp = jitter->timestamp[i]+jitter->span[i];
+      if (incomplete)
+         return JITTER_BUFFER_INCOMPLETE;
+      else
+         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;
+   
+   /* Adjusting the buffering bssed on the amount of packets that are early/on time/late */   
+   if (late_ratio_short > .1 || late_ratio_long > .03)
+   {
+      /* If too many packets are arriving late */
+      jitter->shortterm_margin[MAX_MARGIN-1] += jitter->shortterm_margin[MAX_MARGIN-2];
+      jitter->longterm_margin[MAX_MARGIN-1] += jitter->longterm_margin[MAX_MARGIN-2];
+      for (i=MAX_MARGIN-3;i>=0;i--)
+      {
+         jitter->shortterm_margin[i+1] = jitter->shortterm_margin[i];
+         jitter->longterm_margin[i+1] = jitter->longterm_margin[i];         
+      }
+      jitter->shortterm_margin[0] = 0;
+      jitter->longterm_margin[0] = 0;            
+      jitter->pointer_timestamp -= jitter->tick_size;
+      jitter->current_timestamp -= jitter->tick_size;
+      /*fprintf (stderr, "i");*/
+      /*fprintf (stderr, "interpolate (getting some slack)\n");*/
+   }
+
+   return JITTER_BUFFER_MISSING;
+
+}
+
+/** Get pointer timestamp of jitter buffer */
+int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter)
+{
+   return jitter->pointer_timestamp;
+}
+
+void jitter_buffer_tick(JitterBuffer *jitter)
+{
+   jitter->current_timestamp += jitter->tick_size;
+}
+
+/* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */
+int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset)
+{
+   int i;
+   float late_ratio_short;
+   float late_ratio_long;
+   float ontime_ratio_short;
+   float ontime_ratio_long;
+   float early_ratio_short;
+   float early_ratio_long;
+   
+   if (LT32(jitter->current_timestamp+jitter->tick_size, jitter->pointer_timestamp))
+   {
+      jitter->current_timestamp = jitter->pointer_timestamp;
+      speex_warning("did you forget to call jitter_buffer_tick() by any chance?");
+   }
+   /*fprintf (stderr, "get packet %d %d\n", jitter->pointer_timestamp, jitter->current_timestamp);*/
+
+   /* FIXME: This should be only what remaining of the current tick */
+   late_ratio_short = 0;
+   late_ratio_long = 0;
+   /* Count the proportion of packets that are late */
+   for (i=0;i<LATE_BINS;i++)
+   {
+      late_ratio_short += jitter->shortterm_margin[i];
+      late_ratio_long += jitter->longterm_margin[i];
+   }
+   /* Count the proportion of packets that are just on time */
+   ontime_ratio_short = jitter->shortterm_margin[LATE_BINS];
+   ontime_ratio_long = jitter->longterm_margin[LATE_BINS];
+   early_ratio_short = early_ratio_long = 0;
+   /* Count the proportion of packets that are early */
+   for (i=LATE_BINS+1;i<MAX_MARGIN;i++)
+   {
+      early_ratio_short += jitter->shortterm_margin[i];
+      early_ratio_long += jitter->longterm_margin[i];
+   }
+   
+   /* Adjusting the buffering bssed on the amount of packets that are early/on time/late */   
+   if (late_ratio_short > .1 || late_ratio_long > .03)
+   {
+      /* If too many packets are arriving late */
+      jitter->shortterm_margin[MAX_MARGIN-1] += jitter->shortterm_margin[MAX_MARGIN-2];
+      jitter->longterm_margin[MAX_MARGIN-1] += jitter->longterm_margin[MAX_MARGIN-2];
+      for (i=MAX_MARGIN-3;i>=0;i--)
+      {
+         jitter->shortterm_margin[i+1] = jitter->shortterm_margin[i];
+         jitter->longterm_margin[i+1] = jitter->longterm_margin[i];         
+      }
+      jitter->shortterm_margin[0] = 0;
+      jitter->longterm_margin[0] = 0;            
+      jitter->pointer_timestamp -= jitter->tick_size;
+      jitter->current_timestamp -= jitter->tick_size;
+      jitter->interp_requested = 1;
+      return JITTER_BUFFER_ADJUST_INTERPOLATE;
+   
+   } else if (late_ratio_short + ontime_ratio_short < .005 && late_ratio_long + ontime_ratio_long < .01 && early_ratio_short > .8)
+   {
+      /* Many frames arriving early */
+      jitter->shortterm_margin[0] += jitter->shortterm_margin[1];
+      jitter->longterm_margin[0] += jitter->longterm_margin[1];
+      for (i=1;i<MAX_MARGIN-1;i++)
+      {
+         jitter->shortterm_margin[i] = jitter->shortterm_margin[i+1];
+         jitter->longterm_margin[i] = jitter->longterm_margin[i+1];         
+      }
+      jitter->shortterm_margin[MAX_MARGIN-1] = 0;
+      jitter->longterm_margin[MAX_MARGIN-1] = 0;      
+      /*fprintf (stderr, "drop frame\n");*/
+      /*fprintf (stderr, "d");*/
+      jitter->pointer_timestamp += jitter->tick_size;
+      jitter->current_timestamp += jitter->tick_size;
+      return JITTER_BUFFER_ADJUST_DROP;
+   }
+   
+   return JITTER_BUFFER_ADJUST_OK;
+}
+
+/* Used like the ioctl function to control the jitter buffer parameters */
+int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
+{
+   int count, i;
+   switch(request)
+   {
+      case JITTER_BUFFER_SET_MARGIN:
+         jitter->buffer_margin = *(spx_int32_t*)ptr;
+         break;
+      case JITTER_BUFFER_GET_MARGIN:
+         *(spx_int32_t*)ptr = jitter->buffer_margin;
+         break;
+      case JITTER_BUFFER_GET_AVALIABLE_COUNT:
+         count = 0;
+         for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
+         {
+            if (jitter->buf[i] && LE32(jitter->pointer_timestamp, jitter->timestamp[i]))
+            {
+               count++;
+            }
+         }
+         *(spx_int32_t*)ptr = count;
+         break;
+      default:
+         speex_warning_int("Unknown jitter_buffer_ctl request: ", request);
+         return -1;
+   }
+   return 0;
+}
+
+
+
+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;
+   
+   if (jitter->valid_bits)
+   {
+      /* 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);
+   } 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;i<jitter->frame_size;i++)
+            out[i]=0;
+      }
+   }
+   jitter_buffer_update_delay(jitter->packets, &packet, NULL);
+   jitter_buffer_tick(jitter->packets);
+}
+
+int speex_jitter_get_pointer_timestamp(SpeexJitter *jitter)
+{
+   return jitter_buffer_get_pointer_timestamp(jitter->packets);
+}
diff --git a/3rdparty/speex/libspeex/kiss_fft.c b/3rdparty/speex/libspeex/kiss_fft.c
new file mode 100644
index 0000000..775a257
--- /dev/null
+++ b/3rdparty/speex/libspeex/kiss_fft.c
@@ -0,0 +1,522 @@
+/*
+Copyright (c) 2003-2004, Mark Borgerding
+Copyright (c) 2005-2007, Jean-Marc Valin
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+    * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 "_kiss_fft_guts.h"
+#include "misc.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 void kf_bfly2(
+        kiss_fft_cpx * Fout,
+        const size_t fstride,
+        const kiss_fft_cfg st,
+        int m,
+        int N,
+        int mm
+        )
+{
+    kiss_fft_cpx * Fout2;
+    kiss_fft_cpx * tw1;
+    kiss_fft_cpx t;
+    if (!st->inverse) {
+       int i,j;
+       kiss_fft_cpx * Fout_beg = Fout;
+       for (i=0;i<N;i++)
+       {
+          Fout = Fout_beg + i*mm;
+          Fout2 = Fout + m;
+          tw1 = st->twiddles;
+          for(j=0;j<m;j++)
+          {
+             /* Almost the same as the code path below, except that we divide the input by two
+              (while keeping the best accuracy possible) */
+             spx_word32_t tr, ti;
+             tr = SHR32(SUB32(MULT16_16(Fout2->r , tw1->r),MULT16_16(Fout2->i , tw1->i)), 1);
+             ti = SHR32(ADD32(MULT16_16(Fout2->i , tw1->r),MULT16_16(Fout2->r , tw1->i)), 1);
+             tw1 += fstride;
+             Fout2->r = PSHR32(SUB32(SHL32(EXTEND32(Fout->r), 14), tr), 15);
+             Fout2->i = PSHR32(SUB32(SHL32(EXTEND32(Fout->i), 14), ti), 15);
+             Fout->r = PSHR32(ADD32(SHL32(EXTEND32(Fout->r), 14), tr), 15);
+             Fout->i = PSHR32(ADD32(SHL32(EXTEND32(Fout->i), 14), ti), 15);
+             ++Fout2;
+             ++Fout;
+          }
+       }
+    } else {
+       int i,j;
+       kiss_fft_cpx * Fout_beg = Fout;
+       for (i=0;i<N;i++)
+       {
+          Fout = Fout_beg + i*mm;
+          Fout2 = Fout + m;
+          tw1 = st->twiddles;
+          for(j=0;j<m;j++)
+          {
+             C_MUL (t,  *Fout2 , *tw1);
+             tw1 += fstride;
+             C_SUB( *Fout2 ,  *Fout , t );
+             C_ADDTO( *Fout ,  t );
+             ++Fout2;
+             ++Fout;
+          }
+       }
+    }
+}
+
+static void kf_bfly4(
+        kiss_fft_cpx * Fout,
+        const size_t fstride,
+        const kiss_fft_cfg st,
+        const size_t m,
+        int N,
+        int mm
+        )
+{
+    kiss_fft_cpx *tw1,*tw2,*tw3;
+    kiss_fft_cpx scratch[6];
+    const size_t m2=2*m;
+    const size_t m3=3*m;
+    int i, j;
+
+    if (st->inverse)
+    {
+       kiss_fft_cpx * Fout_beg = Fout;
+       for (i=0;i<N;i++)
+       {
+          Fout = Fout_beg + i*mm;
+          tw3 = tw2 = tw1 = st->twiddles;
+          for (j=0;j<m;j++)
+          {
+             C_MUL(scratch[0],Fout[m] , *tw1 );
+             C_MUL(scratch[1],Fout[m2] , *tw2 );
+             C_MUL(scratch[2],Fout[m3] , *tw3 );
+             
+             C_SUB( scratch[5] , *Fout, scratch[1] );
+             C_ADDTO(*Fout, scratch[1]);
+             C_ADD( scratch[3] , scratch[0] , scratch[2] );
+             C_SUB( scratch[4] , scratch[0] , scratch[2] );
+             C_SUB( Fout[m2], *Fout, scratch[3] );
+             tw1 += fstride;
+             tw2 += fstride*2;
+             tw3 += fstride*3;
+             C_ADDTO( *Fout , scratch[3] );
+             
+             Fout[m].r = scratch[5].r - scratch[4].i;
+             Fout[m].i = scratch[5].i + scratch[4].r;
+             Fout[m3].r = scratch[5].r + scratch[4].i;
+             Fout[m3].i = scratch[5].i - scratch[4].r;
+             ++Fout;
+          }
+       }
+    } else
+    {
+       kiss_fft_cpx * Fout_beg = Fout;
+       for (i=0;i<N;i++)
+       {
+          Fout = Fout_beg + i*mm;
+          tw3 = tw2 = tw1 = st->twiddles;
+          for (j=0;j<m;j++)
+          {
+             C_MUL4(scratch[0],Fout[m] , *tw1 );
+             C_MUL4(scratch[1],Fout[m2] , *tw2 );
+             C_MUL4(scratch[2],Fout[m3] , *tw3 );
+             
+             Fout->r = PSHR16(Fout->r, 2);
+             Fout->i = PSHR16(Fout->i, 2);
+             C_SUB( scratch[5] , *Fout, scratch[1] );
+             C_ADDTO(*Fout, scratch[1]);
+             C_ADD( scratch[3] , scratch[0] , scratch[2] );
+             C_SUB( scratch[4] , scratch[0] , scratch[2] );
+             Fout[m2].r = PSHR16(Fout[m2].r, 2);
+             Fout[m2].i = PSHR16(Fout[m2].i, 2);
+             C_SUB( Fout[m2], *Fout, scratch[3] );
+             tw1 += fstride;
+             tw2 += fstride*2;
+             tw3 += fstride*3;
+             C_ADDTO( *Fout , scratch[3] );
+             
+             Fout[m].r = scratch[5].r + scratch[4].i;
+             Fout[m].i = scratch[5].i - scratch[4].r;
+             Fout[m3].r = scratch[5].r - scratch[4].i;
+             Fout[m3].i = scratch[5].i + scratch[4].r;
+             ++Fout;
+          }
+       }
+    }
+}
+
+static void kf_bfly3(
+         kiss_fft_cpx * Fout,
+         const size_t fstride,
+         const kiss_fft_cfg st,
+         size_t m
+         )
+{
+     size_t k=m;
+     const size_t m2 = 2*m;
+     kiss_fft_cpx *tw1,*tw2;
+     kiss_fft_cpx scratch[5];
+     kiss_fft_cpx epi3;
+     epi3 = st->twiddles[fstride*m];
+
+     tw1=tw2=st->twiddles;
+
+     do{
+        if (!st->inverse) {
+         C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3);
+	}
+
+         C_MUL(scratch[1],Fout[m] , *tw1);
+         C_MUL(scratch[2],Fout[m2] , *tw2);
+
+         C_ADD(scratch[3],scratch[1],scratch[2]);
+         C_SUB(scratch[0],scratch[1],scratch[2]);
+         tw1 += fstride;
+         tw2 += fstride*2;
+
+         Fout[m].r = Fout->r - HALF_OF(scratch[3].r);
+         Fout[m].i = Fout->i - HALF_OF(scratch[3].i);
+
+         C_MULBYSCALAR( scratch[0] , epi3.i );
+
+         C_ADDTO(*Fout,scratch[3]);
+
+         Fout[m2].r = Fout[m].r + scratch[0].i;
+         Fout[m2].i = Fout[m].i - scratch[0].r;
+
+         Fout[m].r -= scratch[0].i;
+         Fout[m].i += scratch[0].r;
+
+         ++Fout;
+     }while(--k);
+}
+
+static void kf_bfly5(
+        kiss_fft_cpx * Fout,
+        const size_t fstride,
+        const kiss_fft_cfg st,
+        int m
+        )
+{
+    kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
+    int u;
+    kiss_fft_cpx scratch[13];
+    kiss_fft_cpx * twiddles = st->twiddles;
+    kiss_fft_cpx *tw;
+    kiss_fft_cpx ya,yb;
+    ya = twiddles[fstride*m];
+    yb = twiddles[fstride*2*m];
+
+    Fout0=Fout;
+    Fout1=Fout0+m;
+    Fout2=Fout0+2*m;
+    Fout3=Fout0+3*m;
+    Fout4=Fout0+4*m;
+
+    tw=st->twiddles;
+    for ( u=0; u<m; ++u ) {
+        if (!st->inverse) {
+        C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5);
+	}
+        scratch[0] = *Fout0;
+
+        C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
+        C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
+        C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
+        C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);
+
+        C_ADD( scratch[7],scratch[1],scratch[4]);
+        C_SUB( scratch[10],scratch[1],scratch[4]);
+        C_ADD( scratch[8],scratch[2],scratch[3]);
+        C_SUB( scratch[9],scratch[2],scratch[3]);
+
+        Fout0->r += scratch[7].r + scratch[8].r;
+        Fout0->i += scratch[7].i + scratch[8].i;
+
+        scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r);
+        scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r);
+
+        scratch[6].r =  S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i);
+        scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i);
+
+        C_SUB(*Fout1,scratch[5],scratch[6]);
+        C_ADD(*Fout4,scratch[5],scratch[6]);
+
+        scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r);
+        scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r);
+        scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i);
+        scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i);
+
+        C_ADD(*Fout2,scratch[11],scratch[12]);
+        C_SUB(*Fout3,scratch[11],scratch[12]);
+
+        ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
+    }
+}
+
+/* perform the butterfly for one stage of a mixed radix FFT */
+static void kf_bfly_generic(
+        kiss_fft_cpx * Fout,
+        const size_t fstride,
+        const kiss_fft_cfg st,
+        int m,
+        int p
+        )
+{
+    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);*/
+    if (p>17)
+       speex_error("KissFFT: max radix supported is 17");
+    
+    for ( u=0; u<m; ++u ) {
+        k=u;
+        for ( q1=0 ; q1<p ; ++q1 ) {
+            scratchbuf[q1] = Fout[ k  ];
+        if (!st->inverse) {
+            C_FIXDIV(scratchbuf[q1],p);
+	}
+            k += m;
+        }
+
+        k=u;
+        for ( q1=0 ; q1<p ; ++q1 ) {
+            int twidx=0;
+            Fout[ k ] = scratchbuf[0];
+            for (q=1;q<p;++q ) {
+                twidx += fstride * k;
+                if (twidx>=Norig) twidx-=Norig;
+                C_MUL(t,scratchbuf[q] , twiddles[twidx] );
+                C_ADDTO( Fout[ k ] ,t);
+            }
+            k += m;
+        }
+    }
+}
+               
+static
+void kf_shuffle(
+         kiss_fft_cpx * Fout,
+         const kiss_fft_cpx * f,
+         const size_t fstride,
+         int in_stride,
+         int * factors,
+         const kiss_fft_cfg st
+            )
+{
+   const int p=*factors++; /* the radix  */
+   const int m=*factors++; /* stage's fft length/p */
+   
+    /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/
+   if (m==1)
+   {
+      int j;
+      for (j=0;j<p;j++)
+      {
+         Fout[j] = *f;
+         f += fstride*in_stride;
+      }
+   } else {
+      int j;
+      for (j=0;j<p;j++)
+      {
+         kf_shuffle( Fout , f, fstride*p, in_stride, factors,st);
+         f += fstride*in_stride;
+         Fout += m;
+      }
+   }
+}
+
+static
+void kf_work(
+        kiss_fft_cpx * Fout,
+        const kiss_fft_cpx * f,
+        const size_t fstride,
+        int in_stride,
+        int * factors,
+        const kiss_fft_cfg st,
+        int N,
+        int s2,
+        int m2
+        )
+{
+   int i;
+    kiss_fft_cpx * Fout_beg=Fout;
+    const int p=*factors++; /* the radix  */
+    const int m=*factors++; /* stage's fft length/p */
+#if 0
+    /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/
+    if (m==1)
+    {
+    /*   int j;
+       for (j=0;j<p;j++)
+       {
+          Fout[j] = *f;
+          f += fstride*in_stride;
+       }*/
+    } else {
+       int j;
+       for (j=0;j<p;j++)
+       {
+          kf_work( Fout , f, fstride*p, in_stride, factors,st, N*p, fstride*in_stride, m);
+          f += fstride*in_stride;
+          Fout += m;
+       }
+    }
+
+    Fout=Fout_beg;
+
+    switch (p) {
+        case 2: kf_bfly2(Fout,fstride,st,m); break;
+        case 3: kf_bfly3(Fout,fstride,st,m); break; 
+        case 4: kf_bfly4(Fout,fstride,st,m); break;
+        case 5: kf_bfly5(Fout,fstride,st,m); break; 
+        default: kf_bfly_generic(Fout,fstride,st,m,p); break;
+    }
+#else
+    /*printf ("fft %d %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N, m2);*/
+    if (m==1) 
+    {
+       /*for (i=0;i<N;i++)
+       {
+          int j;
+          Fout = Fout_beg+i*m2;
+          const kiss_fft_cpx * f2 = f+i*s2;
+          for (j=0;j<p;j++)
+          {
+             *Fout++ = *f2;
+             f2 += fstride*in_stride;
+          }
+       }*/
+    }else{
+       kf_work( Fout , f, fstride*p, in_stride, factors,st, N*p, fstride*in_stride, m);
+    }
+
+    
+       
+       
+       switch (p) {
+          case 2: kf_bfly2(Fout,fstride,st,m, N, m2); break;
+          case 3: for (i=0;i<N;i++){Fout=Fout_beg+i*m2; kf_bfly3(Fout,fstride,st,m);} break; 
+          case 4: kf_bfly4(Fout,fstride,st,m, N, m2); break;
+          case 5: for (i=0;i<N;i++){Fout=Fout_beg+i*m2; kf_bfly5(Fout,fstride,st,m);} break; 
+          default: for (i=0;i<N;i++){Fout=Fout_beg+i*m2; kf_bfly_generic(Fout,fstride,st,m,p);} break;
+    }    
+#endif
+}
+
+/*  facbuf is populated by p1,m1,p2,m2, ...
+    where 
+    p[i] * m[i] = m[i-1]
+    m0 = n                  */
+static 
+void kf_factor(int n,int * facbuf)
+{
+    int p=4;
+
+    /*factor out powers of 4, powers of 2, then any remaining primes */
+    do {
+        while (n % p) {
+            switch (p) {
+                case 4: p = 2; break;
+                case 2: p = 3; break;
+                default: p += 2; break;
+            }
+            if (p>32000 || (spx_int32_t)p*(spx_int32_t)p > n)
+                p = n;          /* no more factors, skip to end */
+        }
+        n /= p;
+        *facbuf++ = p;
+        *facbuf++ = n;
+    } while (n > 1);
+}
+/*
+ *
+ * User-callable function to allocate all necessary storage space for the fft.
+ *
+ * The return value is a contiguous block of memory, allocated with malloc.  As such,
+ * It can be freed with free(), rather than a kiss_fft-specific function.
+ * */
+kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem )
+{
+    kiss_fft_cfg st=NULL;
+    size_t memneeded = sizeof(struct kiss_fft_state)
+        + sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/
+
+    if ( lenmem==NULL ) {
+        st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded );
+    }else{
+        if (mem != NULL && *lenmem >= memneeded)
+            st = (kiss_fft_cfg)mem;
+        *lenmem = memneeded;
+    }
+    if (st) {
+        int i;
+        st->nfft=nfft;
+        st->inverse = inverse_fft;
+#ifdef FIXED_POINT
+        for (i=0;i<nfft;++i) {
+            spx_word32_t phase = i;
+            if (!st->inverse)
+                phase = -phase;
+            kf_cexp2(st->twiddles+i, DIV32(SHL32(phase,17),nfft));
+        }
+#else
+        for (i=0;i<nfft;++i) {
+           const double pi=3.14159265358979323846264338327;
+           double phase = ( -2*pi /nfft ) * i;
+           if (st->inverse)
+              phase *= -1;
+           kf_cexp(st->twiddles+i, phase );
+        }
+#endif
+        kf_factor(nfft,st->factors);
+    }
+    return st;
+}
+
+
+
+    
+void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride)
+{
+    if (fin == fout) 
+    {
+       speex_error("In-place FFT not supported");
+       /*CHECKBUF(tmpbuf,ntmpbuf,st->nfft);
+       kf_work(tmpbuf,fin,1,in_stride, st->factors,st);
+       speex_move(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft);*/
+    } else {
+       kf_shuffle( fout, fin, 1,in_stride, st->factors,st);
+       kf_work( fout, fin, 1,in_stride, st->factors,st, 1, in_stride, 1);
+    }
+}
+
+void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
+{
+    kiss_fft_stride(cfg,fin,fout,1);
+}
+
diff --git a/3rdparty/speex/libspeex/kiss_fft.h b/3rdparty/speex/libspeex/kiss_fft.h
new file mode 100644
index 0000000..54627e7
--- /dev/null
+++ b/3rdparty/speex/libspeex/kiss_fft.h
@@ -0,0 +1,108 @@
+#ifndef KISS_FFT_H
+#define KISS_FFT_H
+
+#include <stdlib.h>
+#include <math.h>
+#include "misc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ ATTENTION!
+ If you would like a :
+ -- a utility that will handle the caching of fft objects
+ -- real-only (no imaginary time component ) FFT
+ -- a multi-dimensional FFT
+ -- a command-line utility to perform ffts
+ -- a command-line utility to perform fast-convolution filtering
+
+ Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c
+  in the tools/ directory.
+*/
+
+#ifdef USE_SIMD
+# include <xmmintrin.h>
+# define kiss_fft_scalar __m128
+#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes)
+#else	
+#define KISS_FFT_MALLOC speex_alloc
+#endif	
+
+
+#ifdef FIXED_POINT
+#include "misc.h"	
+#  define kiss_fft_scalar spx_int16_t
+#else
+# ifndef kiss_fft_scalar
+/*  default is float */
+#   define kiss_fft_scalar float
+# endif
+#endif
+
+typedef struct {
+    kiss_fft_scalar r;
+    kiss_fft_scalar i;
+}kiss_fft_cpx;
+
+typedef struct kiss_fft_state* kiss_fft_cfg;
+
+/* 
+ *  kiss_fft_alloc
+ *  
+ *  Initialize a FFT (or IFFT) algorithm's cfg/state buffer.
+ *
+ *  typical usage:      kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL);
+ *
+ *  The return value from fft_alloc is a cfg buffer used internally
+ *  by the fft routine or NULL.
+ *
+ *  If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc.
+ *  The returned value should be free()d when done to avoid memory leaks.
+ *  
+ *  The state can be placed in a user supplied buffer 'mem':
+ *  If lenmem is not NULL and mem is not NULL and *lenmem is large enough,
+ *      then the function places the cfg in mem and the size used in *lenmem
+ *      and returns mem.
+ *  
+ *  If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough),
+ *      then the function returns NULL and places the minimum cfg 
+ *      buffer size in *lenmem.
+ * */
+
+kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem); 
+
+/*
+ * kiss_fft(cfg,in_out_buf)
+ *
+ * Perform an FFT on a complex input buffer.
+ * for a forward FFT,
+ * fin should be  f[0] , f[1] , ... ,f[nfft-1]
+ * fout will be   F[0] , F[1] , ... ,F[nfft-1]
+ * Note that each element is complex and can be accessed like
+    f[k].r and f[k].i
+ * */
+void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
+
+/*
+ A more generic version of the above function. It reads its input from every Nth sample.
+ * */
+void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride);
+
+/* If kiss_fft_alloc allocated a buffer, it is one contiguous 
+   buffer and can be simply free()d when no longer needed*/
+#define kiss_fft_free speex_free
+
+/*
+ Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up 
+ your compiler output to call this before you exit.
+*/
+void kiss_fft_cleanup(void);
+	
+
+#ifdef __cplusplus
+} 
+#endif
+
+#endif
diff --git a/3rdparty/speex/libspeex/kiss_fftr.c b/3rdparty/speex/libspeex/kiss_fftr.c
new file mode 100644
index 0000000..392945c
--- /dev/null
+++ b/3rdparty/speex/libspeex/kiss_fftr.c
@@ -0,0 +1,296 @@
+/*
+Copyright (c) 2003-2004, Mark Borgerding
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+    * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 "kiss_fftr.h"
+#include "_kiss_fft_guts.h"
+
+struct kiss_fftr_state{
+    kiss_fft_cfg substate;
+    kiss_fft_cpx * tmpbuf;
+    kiss_fft_cpx * super_twiddles;
+#ifdef USE_SIMD    
+    long pad;
+#endif    
+};
+
+kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem)
+{
+    int i;
+    kiss_fftr_cfg st = NULL;
+    size_t subsize, memneeded;
+
+    if (nfft & 1) {
+        speex_warning("Real FFT optimization must be even.\n");
+        return NULL;
+    }
+    nfft >>= 1;
+
+    kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize);
+    memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 2);
+
+    if (lenmem == NULL) {
+        st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded);
+    } else {
+        if (*lenmem >= memneeded)
+            st = (kiss_fftr_cfg) mem;
+        *lenmem = memneeded;
+    }
+    if (!st)
+        return NULL;
+
+    st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */
+    st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize);
+    st->super_twiddles = st->tmpbuf + nfft;
+    kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize);
+
+#ifdef FIXED_POINT
+    for (i=0;i<nfft;++i) {
+       spx_word32_t phase = i+(nfft>>1);
+       if (!inverse_fft)
+          phase = -phase;
+       kf_cexp2(st->super_twiddles+i, DIV32(SHL32(phase,16),nfft));
+    }
+#else
+    for (i=0;i<nfft;++i) {
+       const double pi=3.14159265358979323846264338327;
+       double phase = pi*(((double)i) /nfft + .5);
+       if (!inverse_fft)
+          phase = -phase;
+       kf_cexp(st->super_twiddles+i, phase );
+    }
+#endif
+    return st;
+}
+
+void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata)
+{
+    /* input buffer timedata is stored row-wise */
+    int k,ncfft;
+    kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc;
+
+    if ( st->substate->inverse) {
+        speex_error("kiss fft usage error: improper alloc\n");
+    }
+
+    ncfft = st->substate->nfft;
+
+    /*perform the parallel fft of two real signals packed in real,imag*/
+    kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf );
+    /* The real part of the DC element of the frequency spectrum in st->tmpbuf
+     * contains the sum of the even-numbered elements of the input time sequence
+     * The imag part is the sum of the odd-numbered elements
+     *
+     * The sum of tdc.r and tdc.i is the sum of the input time sequence. 
+     *      yielding DC of input time sequence
+     * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... 
+     *      yielding Nyquist bin of input time sequence
+     */
+ 
+    tdc.r = st->tmpbuf[0].r;
+    tdc.i = st->tmpbuf[0].i;
+    C_FIXDIV(tdc,2);
+    CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i);
+    CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i);
+    freqdata[0].r = tdc.r + tdc.i;
+    freqdata[ncfft].r = tdc.r - tdc.i;
+#ifdef USE_SIMD    
+    freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0);
+#else
+    freqdata[ncfft].i = freqdata[0].i = 0;
+#endif
+
+    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[k].r = HALF_OF(f1k.r + tw.r);
+        freqdata[k].i = HALF_OF(f1k.i + tw.i);
+        freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r);
+        freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i);
+    }
+}
+
+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_error ("kiss fft usage error: improper alloc\n");
+    }
+
+    ncfft = st->substate->nfft;
+
+    st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r;
+    st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r;
+    /*C_FIXDIV(st->tmpbuf[0],2);*/
+
+    for (k = 1; k <= ncfft / 2; ++k) {
+        kiss_fft_cpx fk, fnkc, fek, fok, tmp;
+        fk = freqdata[k];
+        fnkc.r = freqdata[ncfft - k].r;
+        fnkc.i = -freqdata[ncfft - k].i;
+        /*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);
+}
+
+void kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar *freqdata)
+{
+   /* input buffer timedata is stored row-wise */
+   int k,ncfft;
+   kiss_fft_cpx f2k,tdc;
+   spx_word32_t f1kr, f1ki, twr, twi;
+
+   if ( st->substate->inverse) {
+      speex_error("kiss fft usage error: improper alloc\n");
+   }
+
+   ncfft = st->substate->nfft;
+
+   /*perform the parallel fft of two real signals packed in real,imag*/
+   kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf );
+    /* The real part of the DC element of the frequency spectrum in st->tmpbuf
+   * contains the sum of the even-numbered elements of the input time sequence
+   * The imag part is the sum of the odd-numbered elements
+   *
+   * The sum of tdc.r and tdc.i is the sum of the input time sequence. 
+   *      yielding DC of input time sequence
+   * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... 
+   *      yielding Nyquist bin of input time sequence
+    */
+ 
+   tdc.r = st->tmpbuf[0].r;
+   tdc.i = st->tmpbuf[0].i;
+   C_FIXDIV(tdc,2);
+   CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i);
+   CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i);
+   freqdata[0] = tdc.r + tdc.i;
+   freqdata[2*ncfft-1] = tdc.r - tdc.i;
+
+   for ( k=1;k <= ncfft/2 ; ++k )
+   {
+      /*fpk    = st->tmpbuf[k]; 
+      fpnk.r =   st->tmpbuf[ncfft-k].r;
+      fpnk.i = - st->tmpbuf[ncfft-k].i;
+      C_FIXDIV(fpk,2);
+      C_FIXDIV(fpnk,2);
+
+      C_ADD( f1k, fpk , fpnk );
+      C_SUB( f2k, fpk , fpnk );
+      
+      C_MUL( tw , f2k , st->super_twiddles[k]);
+
+      freqdata[2*k-1] = HALF_OF(f1k.r + tw.r);
+      freqdata[2*k] = HALF_OF(f1k.i + tw.i);
+      freqdata[2*(ncfft-k)-1] = HALF_OF(f1k.r - tw.r);
+      freqdata[2*(ncfft-k)] = HALF_OF(tw.i - f1k.i);
+      */
+
+      /*f1k.r = PSHR32(ADD32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1);
+      f1k.i = PSHR32(SUB32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1);
+      f2k.r = PSHR32(SUB32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1);
+      f2k.i = SHR32(ADD32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1);
+      
+      C_MUL( tw , f2k , st->super_twiddles[k]);
+
+      freqdata[2*k-1] = HALF_OF(f1k.r + tw.r);
+      freqdata[2*k] = HALF_OF(f1k.i + tw.i);
+      freqdata[2*(ncfft-k)-1] = HALF_OF(f1k.r - tw.r);
+      freqdata[2*(ncfft-k)] = HALF_OF(tw.i - f1k.i);
+   */
+      f2k.r = SHR32(SUB32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1);
+      f2k.i = PSHR32(ADD32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1);
+      
+      f1kr = SHL32(ADD32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),13);
+      f1ki = SHL32(SUB32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),13);
+      
+      twr = SHR32(SUB32(MULT16_16(f2k.r,st->super_twiddles[k].r),MULT16_16(f2k.i,st->super_twiddles[k].i)), 1);
+      twi = SHR32(ADD32(MULT16_16(f2k.i,st->super_twiddles[k].r),MULT16_16(f2k.r,st->super_twiddles[k].i)), 1);
+      
+#ifdef FIXED_POINT
+      freqdata[2*k-1] = PSHR32(f1kr + twr, 15);
+      freqdata[2*k] = PSHR32(f1ki + twi, 15);
+      freqdata[2*(ncfft-k)-1] = PSHR32(f1kr - twr, 15);
+      freqdata[2*(ncfft-k)] = PSHR32(twi - f1ki, 15);
+#else
+      freqdata[2*k-1] = .5f*(f1kr + twr);
+      freqdata[2*k] = .5f*(f1ki + twi);
+      freqdata[2*(ncfft-k)-1] = .5f*(f1kr - twr);
+      freqdata[2*(ncfft-k)] = .5f*(twi - f1ki);
+      
+#endif
+   }
+}
+
+void kiss_fftri2(kiss_fftr_cfg st,const kiss_fft_scalar *freqdata,kiss_fft_scalar *timedata)
+{
+   /* input buffer timedata is stored row-wise */
+   int k, ncfft;
+
+   if (st->substate->inverse == 0) {
+      speex_error ("kiss fft usage error: improper alloc\n");
+   }
+
+   ncfft = st->substate->nfft;
+
+   st->tmpbuf[0].r = freqdata[0] + freqdata[2*ncfft-1];
+   st->tmpbuf[0].i = freqdata[0] - freqdata[2*ncfft-1];
+   /*C_FIXDIV(st->tmpbuf[0],2);*/
+
+   for (k = 1; k <= ncfft / 2; ++k) {
+      kiss_fft_cpx fk, fnkc, fek, fok, tmp;
+      fk.r = freqdata[2*k-1];
+      fk.i = freqdata[2*k];
+      fnkc.r = freqdata[2*(ncfft - k)-1];
+      fnkc.i = -freqdata[2*(ncfft - k)];
+        /*C_FIXDIV( fk , 2 );
+      C_FIXDIV( fnkc , 2 );*/
+
+      C_ADD (fek, fk, fnkc);
+      C_SUB (tmp, fk, fnkc);
+      C_MUL (fok, tmp, st->super_twiddles[k]);
+      C_ADD (st->tmpbuf[k],     fek, fok);
+      C_SUB (st->tmpbuf[ncfft - k], fek, fok);
+#ifdef USE_SIMD        
+      st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0);
+#else
+      st->tmpbuf[ncfft - k].i *= -1;
+#endif
+   }
+   kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata);
+}
diff --git a/3rdparty/speex/libspeex/kiss_fftr.h b/3rdparty/speex/libspeex/kiss_fftr.h
new file mode 100644
index 0000000..7bfb423
--- /dev/null
+++ b/3rdparty/speex/libspeex/kiss_fftr.h
@@ -0,0 +1,51 @@
+#ifndef KISS_FTR_H
+#define KISS_FTR_H
+
+#include "kiss_fft.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    
+/* 
+ 
+ Real optimized version can save about 45% cpu time vs. complex fft of a real seq.
+
+ 
+ 
+ */
+
+typedef struct kiss_fftr_state *kiss_fftr_cfg;
+
+
+kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem);
+/*
+ nfft must be even
+
+ If you don't care to allocate space, use mem = lenmem = NULL 
+*/
+
+
+void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata);
+/*
+ input timedata has nfft scalar points
+ 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
+*/
+
+#define kiss_fftr_free speex_free
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/3rdparty/speex/libspeex/lbr_48k_tables.c b/3rdparty/speex/libspeex/lbr_48k_tables.c
new file mode 100644
index 0000000..d4d80dc
--- /dev/null
+++ b/3rdparty/speex/libspeex/lbr_48k_tables.c
@@ -0,0 +1,678 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: lbr_48k_tables.c
+
+   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
+
+
+const int dummy_epic_48k_variable=0;
+#ifdef EPIC_48K
+
+const signed char gain_cdbk_ulbr[256] = {
+-31, -48, -30, 10,
+-19, -10, -18, 25,
+-33, -22, -45, 12,
+-5, -56, -43, 31,
+-30, -56, -3, 28,
+-59, -17, -52, 31,
+-41, -60, -58, 32,
+-64, -47, -22, 29,
+-30, -31, -31, 2,
+-29, -14, -31, 11,
+-22, -37, -58, 21,
+-31, -44, 13, 29,
+-37, 0, 1, 35,
+-46, -55, -35, 20, 
+-56, -14, -53, 32,
+-8, 1, -36, 31,
+-29, -15, -27, 13,
+-29, -39, -28, 7,
+-43, -5, 3, 37,
+-51, -27, -54, 23,
+10, -46, -36, 30,
+3, -3, -42, 37,
+-27, 16, -22, 32,
+-34, -52, 13, 34,
+-31, -21, -28, 8,
+-34, -45, -40, 12,
+-20, -48, 4, 32,
+-40, -27, 16, 31,
+-6, 11, -44, 41,
+-35, 12, -5, 37,
+19, -33, -37, 29,
+-29, 18, -32, 27,
+-29, -23, -19, 13,
+16, -47, -28, 34,
+-34, -30, 17, 27,
+-20, 2, -26, 26,
+-38, -40, -36, 9,
+15, -14, -40, 37,
+-39, 14, -9, 38,
+-15, 25, -39, 41,
+-26, 19, -32, 29,
+-39, 17, -14, 37,
+10, -36, -26, 26,
+14, -13, -40, 37,
+-29, -21, -12, 17,
+-8, 19, -39, 41,
+-36, -18, 15, 33,
+-32, -38, -38, 6,
+-19, 4, -23, 29,
+-38, -7, 11, 37,
+9, -10, -39, 35,
+-37, 24, -19, 37,
+-34, -5, -8, 27,
+-20, 23, -41, 38,
+-4, 17, -31, 39,
+-17, -26, -26, 14,
+-24, 28, -36, 36,
+-7, 15, -39, 40,
+-42, 16, -11, 40,
+-29, 14, -6, 38,
+-36, 28, -27, 35,
+-21, 5, -26, 27,
+11, -9, -39, 37,
+-38, -7, 13, 38
+};
+
+
+const signed char exc_12_32_table[384] = {
+34, 55, 9, 55, 4, 44, -2, 25, 4, -6, 13, -22, 
+20, 26, -13, -56, -37, 18, 5, 28, 4, 10, 6, -7, 
+37, -24, -31, 22, 12, -6, -4, -7, 2, 0, -3, -2, 
+-16, -13, -1, 9, -2, 4, 6, 5, -3, 3, 8, -1, 
+-1, -6, -2, -1, 8, 24, 19, 33, -73, -53, 6, -18, 
+14, 7, 11, 8, -33, -94, -5, 7, 0, 44, 1, 19, 
+-9, -7, -34, -16, 8, 2, 5, 0, 3, 1, -2, 3, 
+-22, 6, -2, 12, 16, 30, 39, 25, 25, 2, 10, -2, 
+-1, -40, -6, -51, -5, -48, -9, -33, -14, -1, -24, 15, 
+104, 39, 12, -9, -20, -12, -30, -10, -31, -7, -30, -8, 
+-71, -53, -4, -11, 9, -10, 7, -10, 10, -1, 11, 8, 
+24, 14, 6, -3, 10, 8, 8, 11, -6, 11, 0, -2, 
+-6, -2, 1, -1, -3, 8, -41, 27, 57, -7, 11, -16, 
+-61, 50, 10, -10, 4, -13, 14, -7, 1, 5, -4, 4, 
+0, 2, -1, -2, -1, 1, 1, 0, -1, -1, -2, -3, 
+-3, -15, 69, 60, 10, -10, -10, -29, -21, -7, -16, 2, 
+24, -32, 24, -18, -14, -2, -11, 11, -6, 10, 1, 3, 
+24, -10, 14, 18, -13, 17, -16, 4, -3, -21, -3, -11, 
+-19, 12, -14, 26, 20, -9, 24, -15, 18, 1, -32, -2, 
+-1, 8, -3, 4, 11, -47, 7, 46, -4, -10, -10, -2, 
+-24, 29, -33, 6, -20, -3, 0, -12, 5, -30, 8, -13, 
+28, 9, 5, -11, 0, -14, -13, -22, -12, -8, -4, 1, 
+-6, 28, 45, -18, -31, -5, 1, 2, 1, 5, 0, -3, 
+-19, -10, 10, 27, 8, -16, -28, -9, 2, -5, 8, -1, 
+100, -49, 4, -43, 25, -7, 1, 9, -13, 13, -18, 13, 
+-1, -1, 0, 2, -2, -8, 9, -46, -7, 70, 23, 7, 
+-103, 20, 8, 42, -5, 21, -4, 4, 1, -8, 16, -8, 
+3, 3, 8, 4, 7, -3, -3, -4, 9, 6, 2, 13, 
+6, 3, -15, 11, -43, 31, 40, -13, 12, -21, -2, -3, 
+-10, -9, 16, -35, 31, -3, -12, 8, -34, 7, 12, 22, 
+-3, -4, -7, -12, 24, 53, -19, -43, 4, -3, -4, 6, 
+-18, -30, -58, -17, -11, 17, 23, 34, 30, 28, 28, 15, 
+};
+
+
+const signed char cdbk_lsp_vlbr[5120]={
+23, 34, 108, 100, 102, 82, 69, 48, 52, 25,
+0, -37, -55, -78, -111, -79, 58, 57, 45, 32,
+27, -9, -12, -14, -41, -29, -17, -41, 44, 35,
+-24, -68, -72, 61, 100, 73, 100, 80, 70, 37,
+12, -5, 22, 11, -10, -40, -33, -17, 19, 12,
+-20, -57, -94, -92, 56, 71, 48, 31, 22, -5,
+41, 28, 6, -6, -12, -39, -18, -16, -30, -23,
+65, 54, 41, 28, 23, 9, 26, 18, 22, 6,
+17, -16, -33, -54, -87, -79, 8, -8, 44, 35,
+-20, -62, -78, 22, 78, 47, 44, 33, 26, 14,
+8, 1, 45, 47, 72, 68, 55, 31, 36, 17,
+-27, -68, -86, -65, -10, 23, 8, -22, -31, 25,
+-4, -38, -55, -68, -96, -118, -39, 30, 28, 31,
+-21, -66, -47, 99, 91, 68, 78, 56, 64, 36,
+33, 22, 13, -13, -36, -22, 44, 37, 54, 33,
+-31, -76, -106, -100, -5, 21, 7, -17, 13, 48,
+-26, -65, -84, -84, -46, 67, 97, 66, 58, 31,
+-20, -52, -32, -20, 3, 16, 27, 40, 54, 29,
+-6, -35, -56, -64, -8, -31, -36, 21, 26, -3,
+32, 23, 1, -23, -19, -44, -45, -7, 10, -10,
+-24, -55, 2, 67, 72, 85, 90, 74, 77, 45,
+-21, -58, -45, -49, 16, 34, 13, -15, -16, 16,
+8, -31, -34, -61, -83, 10, 24, 8, 56, 25,
+-8, -49, -74, -95, -123, -77, 6, 40, 46, 42,
+-21, -60, -59, -34, -12, 27, 8, -19, -48, -17,
+-25, -66, -78, -73, -81, -16, 14, 0, -2, 33,
+78, 79, 69, 49, 44, 32, 50, 44, 46, 22,
+24, 9, -4, -18, -37, -56, 22, 34, 22, 11,
+-19, -59, -85, -41, 46, 72, 60, 33, 29, -3,
+-21, -66, -70, 65, 92, 57, 61, 41, 40, 23,
+-4, -41, -60, -72, -102, -106, 4, 56, 57, 31,
+-5, -48, -62, -91, -109, 1, 76, 54, 72, 39,
+-21, -61, -86, -46, -34, -39, 42, 25, 15, 12,
+5, -16, -36, -56, 5, 18, 11, 13, 52, 23,
+12, -6, 30, 40, 59, 40, 27, 8, 19, 6,
+25, 8, -9, -19, -25, -53, -40, -38, -46, -4,
+-17, -59, -83, 2, 58, 29, 18, -2, -17, -5,
+-35, -80, -111, -117, -41, -9, 14, 23, 36, 56,
+48, 67, 93, 71, 77, 91, 110, 95, 83, 47,
+-25, -62, -97, -93, 76, 96, 73, 52, 61, 28,
+-9, -55, -46, 49, 33, 8, 1, -25, 28, 23,
+-10, -47, -60, -45, -62, -58, 56, 57, 48, 28,
+34, 12, -9, 0, 34, 4, 6, 11, 3, -18,
+21, -9, -16, -13, -39, -41, 14, -8, 33, 28,
+-7, -49, -61, 15, 34, 3, 2, -13, -28, -17,
+-14, -50, -46, -65, -76, -13, -10, -29, -30, 22,
+-28, -68, -97, -98, -8, 38, 36, 26, 25, 15,
+6, -33, -9, 1, -28, -11, -19, -24, 61, 36,
+-15, -60, -19, 81, 58, 52, 42, 28, 66, 36,
+-15, -52, -71, -15, 11, -13, 38, 28, 11, -4,
+34, 1, -9, -27, -57, -19, 36, 6, 14, 0,
+-1, -43, -14, 16, -12, -5, -14, -29, -33, -32,
+-13, -57, -75, -100, -111, 1, 2, 13, 48, 33,
+12, 16, 100, 85, 69, 49, 40, 29, 46, 23,
+-4, -26, -41, -44, -7, -26, -39, -27, 18, 0,
+-4, -47, -51, 17, 7, -19, 13, -10, -16, 9,
+-24, -63, -93, -53, 25, 14, 73, 51, 35, 8,
+-34, -77, -106, -83, -51, -47, 2, 12, 41, 53,
+-13, -47, -67, -44, 42, 20, 24, 33, 21, -3,
+11, -15, -29, -51, -79, -88, 22, 56, 43, 20,
+11, -22, -37, -1, 61, 40, 28, 24, 22, -6,
+-3, -33, -50, -66, -93, -100, -16, -16, 3, 41,
+-18, -58, -82, -5, 95, 78, 56, 39, 30, 1,
+-6, -47, -28, -26, -36, 49, 55, 51, 71, 35,
+-6, -50, -42, -4, -32, -1, -1, -18, 67, 40,
+-23, -63, -56, -48, -32, 0, -14, -43, -46, 25,
+-17, -61, -63, 13, -1, 28, 23, 10, 67, 36,
+45, 92, 124, 111, 108, 86, 77, 56, 57, 28,
+50, 35, 13, 3, -2, -32, 3, 14, 6, -8,
+12, -17, -24, -42, -67, -23, 67, 49, 64, 38,
+-21, -60, -90, -45, 32, 6, 7, -3, -15, 9,
+-16, -62, -73, 50, 46, 18, 7, -13, 63, 39,
+19, -16, -19, 20, 5, -15, 16, -9, 5, 8,
+-11, -46, -42, -39, -55, -68, -62, -27, -18, 23,
+-23, -61, -67, -71, -29, 44, 32, 10, -15, -12,
+-6, -45, -43, -40, -67, -22, 42, 19, 61, 38,
+9, -13, -38, -37, 40, 30, 15, 9, 11, -16,
+0, -18, -29, -34, -17, -44, -50, -3, 47, 15,
+-3, -46, -26, 20, -10, 16, 20, -2, 43, 18,
+-23, -46, 46, 91, 99, 100, 99, 79, 72, 42,
+-1, -44, -33, -36, -56, 22, 17, 4, 71, 37,
+0, -38, -49, 0, -1, -30, -21, -35, -44, -6,
+-32, -74, -101, -98, -14, -21, -23, 7, 26, 45,
+8, -28, -44, -63, -96, -84, 34, 21, 13, 23,
+10, -24, -38, -17, -29, -53, -16, -41, -14, 23,
+-19, -61, -76, -12, 97, 99, 79, 60, 59, 25,
+5, -11, -26, -54, -26, -8, -13, 3, 25, 4,
+17, 16, 4, -24, -1, 42, 60, 63, 70, 37,
+10, -27, -22, -43, -62, -7, -16, 10, 75, 40,
+-26, -64, -96, -106, -3, 73, 73, 46, 55, 29,
+-2, -45, -43, 45, 46, 17, 37, 10, 30, 32,
+21, -2, -18, -28, -47, -63, -38, -56, -3, 27,
+-17, -48, -9, 9, 3, 28, 50, 58, 73, 44,
+8, -14, -32, -56, -81, -106, -35, 41, 53, 26,
+1, -38, -51, -66, -100, -61, 32, 17, 66, 42,
+17, 5, -6, -21, -26, -52, -36, 23, 56, 22,
+6, -20, -31, -22, -19, -48, 16, 38, 22, -2,
+-25, -67, -93, -51, 82, 62, 71, 69, 63, 35,
+-12, -51, -71, -60, -76, -91, -14, 41, 35, 20,
+-16, -31, 22, 32, 55, 80, 98, 91, 85, 49,
+-21, -63, -92, -6, 57, 27, 36, 11, 60, 39,
+-7, -45, -67, -81, -114, -110, 0, 24, 23, 45,
+-18, -55, -61, -56, -60, -64, -32, -2, 58, 36,
+-3, -33, -51, -24, 19, -10, -19, 4, 14, -15,
+-19, -59, -81, -12, 7, -12, 36, 16, 48, 36,
+17, -13, -32, -49, -78, -95, -1, -3, -10, 25,
+15, 5, 41, 59, 108, 101, 103, 81, 70, 35,
+-14, -52, -37, 15, 93, 83, 66, 50, 47, 15,
+-3, -31, -49, -52, -9, -31, -10, 37, 62, 27,
+-15, -56, -82, -17, 75, 56, 36, 22, 7, -16,
+-24, -63, -93, -84, 25, 94, 98, 65, 60, 31,
+-2, -45, -39, -61, -61, 48, 35, 32, 54, 18,
+-19, -51, -45, -57, -28, -8, 10, 14, 38, 26,
+-2, -46, -38, 45, 26, 22, 48, 21, 63, 40,
+-22, -61, -73, -75, -67, -31, 13, 18, 51, 34,
+-12, -2, -1, -17, -3, -27, -3, 6, -1, -15,
+-16, -59, -78, 10, 36, 9, 4, -18, 33, 22,
+-25, -62, -97, -107, 39, 87, 69, 46, 42, 12,
+11, -7, -30, -36, 19, 2, -10, -7, -4, -24,
+11, -8, 25, 28, 28, 5, -4, -10, 5, -2,
+-10, -48, -37, -17, -38, -9, -2, -19, -30, -22,
+-23, -61, -79, -81, -2, 15, -4, 17, 20, 2,
+25, -14, -3, -10, -38, 1, 14, -14, -9, -27,
+2, -18, -38, -36, -11, -39, -36, -28, -36, -11,
+32, 59, 127, 124, 127, 108, 91, 68, 64, 34,
+3, -32, -37, -10, -25, -46, 12, 1, -17, -24,
+-29, -69, -102, -100, 2, -7, 11, 14, 1, 31,
+30, -6, -4, -16, -44, -5, 3, -9, 66, 40,
+-9, -45, -52, -5, 37, 19, 26, 6, 51, 32,
+-31, -73, -96, -45, -25, -37, -15, -16, 32, 39,
+3, -15, 18, 21, 28, 33, 58, 58, 69, 42,
+-31, -73, -99, -99, -48, 14, 21, 5, 2, 39,
+7, -35, -20, 29, 2, -8, -8, -28, 38, 26,
+-5, -39, -64, -36, 15, -15, -11, -21, -23, 5,
+-8, -51, -56, 15, -1, -14, -8, -31, 36, 22,
+-8, -53, -68, -98, -101, 42, 49, 38, 41, 12,
+10, -27, -22, 4, -23, -21, 30, -1, 22, 26,
+-13, -56, -42, 31, 9, -1, -10, -2, 22, -4,
+15, 8, 56, 57, 45, 55, 57, 46, 72, 44,
+-7, -53, -26, 53, 21, 17, 0, 0, 74, 41,
+3, -18, -2, 0, 19, 17, 42, 36, 47, 26,
+24, -7, -23, -34, -62, -60, 6, -22, 18, 25,
+-11, -42, -46, -61, -83, -99, -67, -11, 28, 39,
+30, -3, -10, -1, -24, -30, -1, -28, 15, 18,
+19, -15, -10, -6, -35, -26, 33, 10, 56, 39,
+-13, -53, -82, -42, 53, 37, 18, 10, -3, -21,
+-21, -60, -89, -46, 89, 94, 71, 46, 42, 9,
+-2, -34, -44, -46, -64, -84, -1, 37, 16, 0,
+-17, -51, -65, -64, -7, -17, -29, -11, 52, 27,
+22, -15, -16, -39, -55, 26, 36, 21, 62, 28,
+-2, -26, -38, -49, -55, -80, -75, 8, 20, 9,
+-6, -47, -61, -82, -103, -17, -15, -25, 53, 40,
+-8, -47, -66, -18, 56, 43, 25, 29, 39, 3,
+-27, -66, -86, -69, -50, -59, -34, -1, 19, 42,
+3, -20, 2, 21, 72, 57, 52, 36, 31, 7,
+-12, -49, -61, -13, -1, -33, 5, 37, 26, 2,
+-27, -69, -92, -62, 2, 43, 88, 67, 64, 36,
+0, -40, -4, -6, -20, 43, 33, 25, 50, 20,
+14, -20, -30, -44, -73, -37, -24, -47, 26, 20,
+31, 53, 111, 118, 127, 126, 121, 99, 85, 46,
+-14, -45, -51, -39, 24, 5, -6, 17, 46, 14,
+-4, -43, -45, -70, -63, 8, 14, 58, 78, 39,
+-8, -47, -66, -84, -114, -55, 10, -8, 32, 40,
+28, 22, 42, 26, 8, -21, -16, -6, 22, 10,
+24, 10, 34, 31, 35, 31, 46, 39, 59, 36,
+-4, -43, -62, -10, 20, -14, 2, 14, -6, -19,
+-21, -62, -89, -22, 62, 33, 30, 16, 15, 15,
+0, -22, -31, -45, -58, -80, -66, 13, 68, 34,
+-16, -45, -6, 7, -6, -17, -14, -15, 2, 2,
+10, -5, -22, -38, -40, -70, -60, -15, -23, 0,
+22, -11, -22, -39, -67, -25, 30, 5, 58, 37,
+-21, -47, 6, 43, 37, 45, 65, 66, 73, 43,
+2, -25, -40, -53, -72, -94, -35, 24, 9, 8,
+-3, 0, -3, -9, 4, -23, -10, 20, 43, 14,
+-2, -41, -60, -9, 57, 32, 17, 16, 6, -19,
+1, -31, -36, -36, -54, -68, -77, -75, 21, 37,
+-19, -32, 79, 90, 92, 81, 67, 47, 52, 28,
+-6, -36, -57, -62, 27, 40, 21, 11, 9, -19,
+-10, -47, -49, -59, -74, -18, -14, -30, 25, 18,
+-23, -69, -82, 60, 66, 40, 75, 54, 65, 38,
+-19, -57, -92, -68, 66, 58, 34, 18, 1, -16,
+-29, -68, -99, -88, -37, -38, 13, 8, 5, 40,
+-22, -63, -75, 14, 15, 7, 75, 58, 59, 34,
+-23, -62, -82, -39, -31, -53, -27, 5, -3, 20,
+13, -26, -20, 22, 2, -3, 35, 13, 54, 39,
+32, 5, -13, -22, -45, -58, -1, -20, -19, 7,
+30, 46, 70, 55, 89, 88, 91, 67, 56, 28,
+-13, -50, -63, -25, -28, -50, -23, -32, -34, 19,
+-13, -54, -65, -9, -20, -37, 29, 6, 11, 25,
+0, -40, -55, -78, -107, -25, 47, 20, 34, 16,
+-20, -58, -96, -103, 38, 43, 27, 30, 15, -1,
+-16, -49, -52, -66, -80, -57, -44, -39, 6, 38,
+0, -38, 5, 13, -8, 23, 24, 1, 7, -9,
+-18, -56, -64, -7, 38, 13, 11, 32, 28, 0,
+14, -3, -20, -17, 4, -26, -34, -8, 19, -9,
+-23, -60, -83, -38, -8, -32, 11, 19, -1, -5,
+-5, -47, -12, 56, 38, 22, 18, -8, -5, -8,
+18, -4, -24, -16, 27, 2, -6, 5, 25, -5,
+13, 0, -19, -35, -23, -45, -59, -30, 19, 3,
+19, -12, -23, 1, -7, -35, -14, -32, -23, 4,
+-23, -64, -67, -22, -27, -5, -5, -20, 20, 5,
+20, 11, 83, 92, 85, 89, 69, 53, 80, 48,
+15, -2, -21, -29, -18, -48, -52, -12, -11, -21,
+-6, -38, -55, -68, -9, 33, 22, 19, 25, -1,
+-8, -46, -49, -67, -64, 16, 8, -6, 32, 15,
+3, -25, -46, -46, 39, 50, 34, 21, 46, 14,
+8, -33, -37, -68, -82, 31, 34, 13, 19, -6,
+33, 0, 5, -7, -32, 2, 22, -3, 35, 17,
+-23, -62, -91, -64, 6, 3, 36, 26, 7, -3,
+-12, -54, -60, 26, 46, 16, 30, 22, 8, -4,
+-23, -61, -40, 31, 58, 73, 88, 77, 74, 41,
+-2, -42, -49, 13, 5, -15, 22, -4, 26, 27,
+-13, -54, -39, 18, 2, -8, -12, 34, 56, 23,
+-20, -31, 27, 23, 24, 28, 39, 33, 47, 27,
+36, 17, -4, -20, -30, -61, -8, 20, 0, -15,
+-10, -51, -72, -82, -111, -73, 34, 25, 19, 38,
+-10, -45, -63, -55, -46, -75, -45, 34, 34, 12,
+6, -18, 29, 26, 7, -9, 0, 5, 38, 22,
+-7, -52, -16, 69, 43, 26, 23, 2, 51, 34,
+-12, -51, -59, -78, -88, 15, 20, 0, -14, 12,
+-3, -36, -59, -45, 60, 49, 28, 20, 16, -13,
+-28, -70, -90, 9, 67, 48, 90, 77, 70, 38,
+-10, -39, -58, -54, 15, -12, 3, 35, 27, -3,
+12, -1, 28, 29, 55, 53, 80, 65, 51, 23,
+-17, -61, -39, 74, 56, 43, 75, 51, 58, 36,
+-30, -71, -93, -43, -29, -26, 4, -19, -14, 37,
+3, -13, -31, -38, 11, -5, -22, -11, 43, 14,
+-25, -65, -80, -79, -71, 3, 37, 32, 20, 9,
+-20, -60, -77, -26, 18, 43, 44, 24, 22, -3,
+-4, -42, -22, -19, -45, -32, -35, -39, -46, 1,
+-25, -59, -27, -10, -7, -4, 7, 13, 25, 12,
+8, -25, -32, -47, -74, -32, 27, 6, 25, 7,
+41, 40, 62, 64, 64, 50, 54, 42, 49, 25,
+-21, -63, -88, -21, 16, -3, -4, -26, 57, 38,
+8, -25, -34, 2, -8, -28, 2, -22, 12, 23,
+-19, -49, 10, 71, 84, 71, 66, 48, 42, 22,
+-20, -58, -89, -57, 62, 44, 33, 36, 25, -1,
+-22, -55, -27, 1, 43, 37, 46, 50, 51, 26,
+1, -38, -46, 22, 34, 4, 20, -2, 3, 9,
+-4, -42, -49, -75, -89, -24, -25, 19, 71, 39,
+5, -28, -45, -43, -63, -75, -17, -38, 14, 30,
+-4, -36, -62, -59, -29, -43, -4, -16, 11, 23,
+-19, -57, -82, -39, 26, 2, -2, 20, 11, -10,
+-28, -68, -92, -70, 9, -1, -15, -30, 11, 31,
+1, -22, -41, -49, -30, -58, -48, 8, 4, -9,
+38, 41, 108, 115, 96, 98, 103, 84, 86, 51,
+15, 1, 58, 46, 26, 6, 16, 18, 41, 24,
+4, -34, -14, -27, -42, 20, 18, 2, 23, 1,
+-22, -59, -83, -70, -22, -42, -26, 29, 29, 15,
+-14, -34, 11, -1, -21, -35, -3, 1, 29, 16,
+-16, -57, -78, -7, 17, -13, 8, -13, -6, 22,
+-22, -32, -21, -20, 20, -4, 10, 13, 12, -4,
+8, -30, -30, -46, -71, -4, 3, -11, 4, -11,
+16, 5, -15, -21, 3, -23, -25, -19, -28, -32,
+-28, -68, -98, -101, -34, 19, 71, 52, 49, 30,
+-18, -57, -82, -56, -56, -66, 15, 12, 1, 29,
+-21, -62, -76, -27, -33, -38, 18, 30, 54, 32,
+3, -36, -10, -17, -34, -3, -8, 32, 63, 27,
+1, -30, -44, -20, -13, -49, -25, 3, -14, -18,
+-26, -68, -80, -46, -28, 17, 42, 37, 58, 34,
+30, 26, 57, 55, 49, 25, 16, 3, 24, 11,
+35, 35, 67, 57, 60, 82, 114, 103, 93, 55,
+18, -8, -23, -32, -53, -68, 15, 11, -6, -7,
+-2, -43, -29, 0, -28, -5, -5, -15, 25, -1,
+4, -13, -35, -45, 14, -6, -2, 19, 16, -9,
+-30, -72, -93, -93, -73, -10, -15, 6, 30, 45,
+-23, -58, -50, -55, -74, -60, -23, 0, 6, 21,
+-4, -40, -63, -24, 7, -19, 4, -18, 27, 28,
+-12, 1, 88, 76, 74, 88, 93, 90, 80, 44,
+-13, -59, -43, 52, 27, 21, 15, 12, 42, 11,
+22, -14, -17, -33, -57, -4, 5, -18, 40, 18,
+-3, -23, -43, -44, 8, -16, -14, -4, -20, -29,
+35, 45, 75, 82, 111, 117, 125, 105, 89, 51,
+-3, -38, -57, -30, 79, 71, 48, 33, 33, 0,
+-17, -62, -57, 66, 67, 35, 29, 5, 22, 17,
+3, -31, -34, -21, -44, -49, 42, 23, 24, 26,
+-23, -62, -74, -49, -30, -30, -37, -50, 9, 35,
+-17, -57, -71, -81, -45, 61, 58, 37, 31, 9,
+3, -7, 28, 14, -2, 0, 40, 41, 58, 33,
+-11, -51, -74, -17, 40, 12, 8, 13, -4, -22,
+-16, -46, -31, -35, -49, -49, -26, -9, -7, -7,
+17, -9, -24, -41, -68, -73, 38, 33, 19, 16,
+-15, -50, -47, -16, -24, -21, 59, 56, 53, 30,
+-14, -54, -57, 2, -17, -33, -34, -21, 4, -4,
+-23, -62, -93, -72, 48, 31, 21, 6, 3, 17,
+-18, -63, -79, 44, 68, 36, 45, 20, 57, 37,
+-29, -72, -99, -111, -86, -31, 7, 25, 39, 55,
+-14, -49, -53, -63, -80, -31, 24, 13, 1, -1,
+-9, -45, -55, -27, -31, -63, -23, 25, 13, -5,
+-20, -61, -80, 7, 44, 16, 54, 40, 32, 17,
+24, 7, -8, -43, -62, -54, -11, 7, 35, 27,
+-12, -55, -59, -48, -69, -4, -1, -12, 68, 39,
+-12, -31, 52, 63, 53, 34, 29, 22, 36, 19,
+-26, -66, -97, -79, 50, 41, 40, 48, 54, 28,
+-2, -37, -41, -2, -11, -30, 29, 16, 4, -2,
+40, 49, 56, 37, 39, 40, 64, 59, 67, 39,
+11, -5, 20, 14, 25, 16, 25, 22, 37, 17,
+-3, -43, -46, -10, -35, -38, -35, -39, 67, 43,
+-7, -47, -33, -39, -60, -12, -18, 11, 43, 11,
+-25, -65, -91, -76, -91, -81, 0, 13, 34, 50,
+-9, -50, -52, 17, 0, -4, 43, 18, 63, 42,
+-8, -15, 15, 41, 56, 35, 51, 45, 51, 29,
+0, -14, -24, -36, -43, -70, -39, 27, 33, 5,
+-25, -62, -81, -66, -12, -26, -16, -4, -13, 21,
+-29, -68, -60, -24, -3, 11, 18, 19, 30, 20,
+1, -35, -42, -30, -57, -51, 13, -17, 3, 22,
+-8, -27, -12, -2, -7, -21, 36, 41, 34, 12,
+-17, -56, -62, -72, -73, -17, -26, 9, 16, 13,
+11, -21, -37, -3, 16, -17, 1, -3, -18, -19,
+15, -20, -19, -22, -49, -30, -7, -29, 3, -2,
+17, -4, 11, 6, 51, 40, 36, 34, 48, 22,
+-19, -55, -29, 37, 68, 49, 45, 33, 42, 23,
+7, -30, -22, 3, -22, -36, -36, -54, 20, 22,
+20, 2, -15, -39, -59, -85, -10, 37, 21, 2,
+-15, -54, -77, -54, 74, 70, 48, 32, 51, 20,
+-25, -64, -70, -75, -52, 17, 6, -20, -30, 26,
+-13, -55, -15, 39, 16, 42, 30, 33, 62, 28,
+-21, -56, -30, -35, 6, 13, -4, -29, 33, 27,
+-17, -55, -75, -31, 3, -28, -26, 16, 18, -4,
+-13, -44, -60, -52, -9, -36, -38, 1, -9, -9,
+-12, -50, -77, -70, 43, 47, 28, 13, 43, 16,
+-13, -57, -80, -104, -113, -30, 43, 45, 52, 39,
+3, -28, -42, -37, -58, -67, 23, 4, 38, 33,
+-21, -64, -74, -22, 43, 83, 81, 56, 62, 32,
+34, 26, 23, 9, 14, 17, 26, 16, 37, 19,
+-5, -48, -49, -75, -65, 9, -6, 41, 45, 15,
+32, 30, 63, 83, 90, 91, 100, 84, 85, 52,
+-19, -54, -68, -71, 11, 30, 13, 1, 63, 37,
+44, 76, 99, 87, 117, 113, 103, 77, 64, 32,
+-16, -45, -12, 30, 27, 15, 57, 49, 42, 22,
+9, -15, -31, -28, -36, -61, -13, -18, -33, -5,
+-12, -55, -8, 82, 64, 47, 42, 21, 27, 9,
+-15, -56, -74, -12, -19, -28, 7, -16, 53, 38,
+-7, -45, -64, -55, -74, -80, 35, 45, 24, 15,
+-25, -48, -34, -42, -6, -27, -9, 9, 13, -7,
+-25, -65, -84, -35, 30, 14, 24, 39, 48, 28,
+-22, -62, -86, -51, 64, 104, 94, 61, 62, 31,
+16, -15, -25, -28, -55, -56, -10, -23, 52, 36,
+10, -10, -22, -46, -71, -92, -45, -13, 16, 26,
+-22, -65, -84, 17, 85, 55, 66, 48, 55, 31,
+-1, -38, -33, -25, -49, -15, 18, -10, 41, 30,
+-3, -24, -47, -60, -30, -46, -17, -13, -27, 1,
+-7, -41, -61, -54, -50, -78, -28, 5, -2, 20,
+17, -12, -27, -4, 8, -27, -5, 23, 14, -12,
+-36, -81, -111, -75, -17, -9, 9, 9, 39, 49,
+-13, -59, -54, 68, 51, 32, 35, 14, 64, 38,
+-11, -44, -69, -57, 11, -11, -5, 3, -16, -15,
+34, 36, 41, 16, -8, -24, 11, 23, 48, 28,
+-17, -42, 8, 17, 45, 69, 71, 55, 49, 23,
+3, -30, -46, -64, -95, -109, 2, 39, 19, 19,
+25, -13, -7, 16, -11, -5, 8, -11, 52, 33,
+-8, -37, -57, -60, 13, 7, -14, -4, 20, -7,
+7, -31, 9, 44, 20, 22, 29, 10, 52, 31,
+3, -22, -36, -53, -80, -77, -35, -41, 54, 41,
+-21, -59, -87, -83, 12, 69, 57, 36, 32, 2,
+6, -14, -34, -42, -4, -32, -27, 10, 4, -20,
+-11, -56, -59, 25, 8, -5, -9, -26, 68, 43,
+22, 13, 40, 39, 73, 81, 95, 88, 82, 45,
+-18, -62, -79, 28, 60, 28, 29, 3, 23, 25,
+6, -31, -39, -55, -85, -32, 7, -17, 48, 30,
+7, -24, -42, -8, 39, 10, 7, 11, 1, -20,
+-1, -36, -26, -30, -48, 2, 46, 26, 35, 14,
+-17, -57, -56, -10, -4, 26, 22, 6, -4, -16,
+-18, -55, -59, -67, -86, -50, 3, 29, 29, 16,
+-25, -61, -33, 2, 26, 25, 23, 10, 24, 16,
+26, 15, -8, -20, 6, -21, -16, 3, 0, -22,
+13, -17, -26, -12, -31, -48, 15, -3, 1, 14,
+4, -27, -33, -21, -29, -53, -52, -64, -42, 22,
+-11, -41, -42, -40, -42, -64, 0, 48, 50, 19,
+-13, -47, -42, -56, -50, 10, 3, -9, -30, -16,
+-4, -47, -12, 14, -13, 21, 13, 6, 73, 40,
+-15, -50, -63, -41, -31, -55, -60, -13, 28, 15,
+-6, -50, -56, -81, -95, 30, 29, 21, 71, 35,
+-14, -58, -65, 37, 40, 9, 18, -10, -4, 20,
+31, 33, 79, 106, 119, 103, 100, 77, 64, 33,
+14, 7, 56, 81, 97, 85, 85, 61, 45, 20,
+-24, -66, -74, -51, -17, 16, 5, -21, 22, 26,
+-1, -25, -38, -24, -2, -35, -26, 21, 34, 1,
+20, 15, 75, 59, 39, 26, 48, 43, 50, 29,
+26, 1, -15, -4, -9, -38, 9, 2, -9, -8,
+20, 14, 19, 13, 2, -16, 24, 25, 19, 3,
+-8, -41, -58, -78, -109, -106, -27, 9, 53, 46,
+17, 5, -13, -25, -24, -54, -20, 2, -21, -25,
+-11, -50, -48, 19, 10, -7, 46, 26, 24, 17,
+-28, -68, -69, -50, -49, -33, -7, 10, 20, 21,
+4, -36, -21, 38, 19, 1, 25, -3, 20, 22,
+-18, -58, -87, -44, 82, 73, 49, 31, 19, -7,
+-21, -61, -78, -44, -58, -66, -9, -23, 10, 40,
+-25, -66, -76, -33, -33, 6, 16, -6, -21, 5,
+-27, -69, -77, 5, -2, -7, 6, 9, 24, 6,
+1, -41, -41, -58, -79, 25, 69, 43, 68, 36,
+-28, -67, -85, -71, -34, 0, 14, 12, -2, 4,
+-2, -33, -55, -37, 37, 25, 6, 6, 29, -4,
+-8, -25, -11, -9, 40, 23, 17, 25, 37, 12,
+-21, -27, 52, 60, 47, 58, 76, 70, 69, 38,
+23, 15, 22, -8, -32, -50, -10, 3, 31, 21,
+-10, -44, -67, -61, -29, -54, 8, 39, 21, 4,
+31, 18, 30, 36, 46, 28, 50, 42, 35, 13,
+-21, -57, -24, -16, -15, 14, 3, -25, -17, 20,
+23, 6, 24, 35, 90, 72, 64, 55, 55, 23,
+7, -28, -42, -19, -36, -50, -15, -40, 29, 28,
+-21, -59, -66, -59, -6, 85, 83, 53, 54, 26,
+2, -20, -42, -52, -27, -49, 5, 9, -9, -8,
+-18, -56, -84, -72, 24, 51, 32, 20, 13, -10,
+-13, -53, -64, -39, -63, -40, 24, 0, 34, 29,
+0, -31, -45, -63, -90, -53, 3, -18, -9, 24,
+-13, -57, -71, 27, 19, -3, 25, -3, 45, 35,
+12, -9, -26, -40, -51, -78, -24, 11, -9, -6,
+-12, -49, -45, -33, -50, -48, -46, -52, 2, 25,
+-14, -56, -84, -108, -122, -50, 4, 22, 42, 53,
+-6, -44, -54, -28, -41, -61, 19, 25, 6, 1,
+-32, -75, -95, -38, -1, -15, 7, 14, 23, 23,
+11, 12, 37, 30, 38, 51, 80, 80, 82, 47,
+-19, -56, -69, -82, -98, -64, -29, 2, 28, 42,
+-18, -49, 3, 34, 41, 39, 32, 18, 21, 7,
+-8, 23, 39, 30, 30, 27, 41, 36, 44, 23,
+-16, -49, -69, -46, 1, -27, 41, 48, 35, 15,
+6, -32, -36, 5, -17, -30, 2, -16, 51, 35,
+-23, -64, -91, -21, 71, 44, 52, 44, 40, 21,
+-22, -55, -40, -20, 62, 52, 38, 29, 27, 5,
+-27, -69, -75, -6, -8, 3, -2, -30, -42, 13,
+2, -29, -42, -10, 29, 2, 15, 30, 26, 0,
+-27, -69, -85, -75, -54, -8, -14, -31, 16, 42,
+-2, -44, -54, -75, -101, -6, 4, -3, 32, 13,
+7, -3, -22, -43, -14, -27, -24, -11, -14, -12,
+-18, -57, -85, -66, 47, 86, 75, 45, 42, 10,
+18, 3, 39, 76, 80, 48, 48, 41, 44, 21,
+-13, -51, -73, -22, -15, -41, 3, -4, -22, 3,
+-10, -50, -63, -9, -23, -42, -6, -30, 11, 28,
+15, -11, -29, -39, -57, -71, -23, -40, -33, 20,
+-2, -40, -48, -5, -21, -25, 31, 7, 53, 35,
+-19, -63, -72, 39, 34, 16, 37, 17, 54, 31,
+-18, -49, -28, -27, -40, -29, 4, 4, 19, 11,
+-1, -43, -41, 24, 15, -12, -4, -31, -4, 23,
+-11, -46, -79, -74, 34, 21, 9, 15, 3, -13,
+-16, -51, -56, -55, 8, 62, 50, 30, 43, 14,
+-1, -25, -27, -32, -46, -62, -66, -36, 53, 32,
+-12, -49, -77, -50, 2, -21, 23, 6, 14, 21,
+-5, -47, -58, -77, -105, -14, 30, 9, 73, 44,
+-24, -52, -4, 10, 13, 13, 27, 27, 42, 24,
+-10, -38, -27, -15, -24, -52, -53, 1, 14, -6,
+-17, -45, -13, 2, 19, 53, 83, 79, 76, 43,
+-21, -62, -86, -48, 40, 17, 14, -9, 40, 30,
+-1, -32, -51, -33, -3, -35, 2, 17, -2, -12,
+-21, -60, -85, -70, 33, 73, 58, 37, 67, 36,
+-1, -45, -39, 37, 17, 3, 18, -8, 53, 35,
+-8, -47, -65, -61, -87, -93, 9, 9, 2, 33,
+-13, -55, -56, -19, -29, 14, 17, 6, 55, 28,
+5, 1, -7, -23, -26, -56, -39, 14, 11, -13,
+-28, -69, -89, -74, -83, -45, 1, 0, 16, 45,
+-3, 5, 91, 104, 119, 111, 97, 76, 72, 39,
+19, 5, -12, -34, -41, -72, -67, 14, 21, 1,
+-17, -49, 15, 27, 13, 6, 2, 12, 27, 10,
+-10, -30, 18, 36, 93, 87, 87, 69, 58, 26,
+37, 32, 64, 54, 53, 67, 78, 73, 80, 48,
+48, 46, 38, 9, -1, 8, 47, 44, 58, 33,
+-23, -61, -88, -76, 27, 14, 9, 36, 36, 10,
+-24, -66, -88, -97, -55, 20, 19, 16, 52, 31,
+4, -16, -1, -8, 2, 0, 15, 13, 29, 14,
+-9, -44, -66, -72, 8, 32, 37, 38, 46, 16,
+-22, -65, -62, 30, 22, 51, 57, 45, 68, 38,
+-4, -42, -53, -33, -54, -53, -4, -18, 62, 40,
+-5, -37, -61, -41, 35, 15, -2, -3, -12, -28,
+-18, -65, -55, 90, 80, 49, 44, 21, 59, 36,
+5, -16, -31, -32, -37, -62, -19, -11, 9, 16,
+-22, -60, -67, -51, -61, -35, -5, -18, -27, 24,
+-18, -55, -39, -42, -40, 20, 25, 6, 6, 7,
+0, -25, -42, -50, -59, -84, -31, -13, -22, 17,
+-32, -73, -100, -89, -21, -10, 18, 38, 31, 23,
+-15, -54, -57, -13, -18, -41, -32, 17, 50, 21,
+-16, -57, -71, -10, -8, -26, -38, -47, 42, 25,
+-17, -58, -82, -7, 33, 3, 30, 11, 13, 24,
+-23, -61, -97, -83, 82, 81, 57, 39, 31, 2,
+26, 32, 104, 86, 62, 55, 77, 70, 74, 43,
+-8, -29, -33, -52, -74, -73, -17, 14, 39, 25,
+-21, -60, -68, -22, 43, 37, 51, 54, 64, 36,
+-5, -30, -50, -52, 22, 7, 10, 13, 0, -20,
+-15, -53, -61, -34, -50, -25, 15, 6, 0, -14,
+-10, -51, -60, 20, 77, 50, 34, 22, 8, -8,
+-8, -45, -52, -59, -76, -35, -43, -49, 47, 40,
+41, 44, 53, 40, 41, 30, 38, 31, 46, 24,
+19, 3, -15, -26, -16, -45, -13, 24, 18, -5,
+-3, -39, -54, -35, -49, -70, 2, -6, -19, 15,
+-13, -53, -36, 6, -3, 45, 50, 30, 33, 10,
+15, -25, -16, -4, -32, 7, 23, 6, 67, 36,
+-21, -58, -87, -71, 10, -12, -16, 19, 10, 0,
+9, -15, -6, 25, 31, 7, 30, 28, 20, 2,
+2, -28, -42, -50, -67, -75, 12, 12, -4, 8,
+-17, -63, -58, 56, 49, 36, 60, 38, 37, 14,
+-13, -48, -38, -29, -44, -25, -20, -33, 38, 20,
+2, -37, -42, -1, -18, -42, 3, -17, -19, 12,
+-20, -60, -73, -7, 12, -13, -22, -38, 4, 10,
+-8, -41, -63, -65, 42, 63, 45, 31, 31, 0,
+-4, -46, -38, -9, -35, 15, 50, 27, 67, 39,
+3, -7, -13, -34, -51, -47, 9, 39, 54, 29,
+-29, -71, -89, -52, -39, -6, 3, 2, 38, 28,
+-14, -42, -13, -15, -19, 0, 20, 12, 37, 25,
+11, -26, -24, -40, -65, -11, -13, -27, 65, 37,
+0, -31, -46, -17, -21, -45, 11, -2, 25, 24,
+51, 91, 102, 87, 85, 63, 57, 42, 48, 23,
+-4, -34, -56, -70, -10, -14, 4, 18, 3, -8,
+-23, -59, -39, -44, -42, -14, -10, -23, -4, 17,
+-2, 4, 35, 63, 69, 75, 82, 63, 78, 48,
+-17, -55, -60, -3, -4, -19, 4, -4, -18, -29,
+2, -20, -36, -50, -32, -59, -16, 30, 16, -6,
+-12, -47, 24, 68, 45, 46, 41, 32, 65, 37,
+-4, -40, -54, -67, -96, -66, -9, -25, 42, 38,
+-15, 13, 58, 58, 84, 104, 119, 104, 89, 51,
+-15, -24, -9, -24, -27, -50, -7, 28, 29, 6,
+-7, -33, -35, -49, -65, -53, -37, -10, 33, 14,
+31, 19, 46, 72, 67, 45, 83, 68, 63, 41,
+-14, -53, -59, -17, 55, 79, 64, 39, 43, 10,
+};
+
+const signed char cdbk_lsp2_vlbr[160]={
+-20, -30, -24, 17, 7, -13, -21, 61, 56, 16,
+12, 1, 10, 77, 32, 3, 7, 3, -25, -31,
+-4, 2, -36, -83, 18, 5, -5, 5, 11, 23,
+-2, -1, -11, -12, -20, -28, 68, 50, -17, -20,
+5, 2, 1, 20, 17, 4, -52, -66, 36, 24,
+-4, -10, 7, -15, -32, 80, 37, 8, -13, -29,
+33, 37, 28, 15, 8, 14, 35, 18, 50, 36,
+-4, -1, 4, -7, 3, 3, -11, -58, -75, 13,
+13, 21, 24, -11, -12, -38, -72, 33, 15, -12,
+-44, -17, 83, 21, 2, 7, 0, 4, 0, -1,
+-25, -42, -51, 33, 20, 15, 30, -13, 9, 32,
+6, 2, -8, 7, -38, -77, 6, -13, -7, 32,
+48, 57, 32, -12, -10, -4, 2, -15, -29, -29,
+2, 10, -9, -16, 79, 44, 7, 12, -5, -18,
+-23, -29, -35, -3, -3, -18, -34, -3, -39, -50,
+-5, -10, -8, -37, -76, 11, -4, -19, 30, 16,
+};
+
+#endif
diff --git a/3rdparty/speex/libspeex/lpc.c b/3rdparty/speex/libspeex/lpc.c
new file mode 100644
index 0000000..fd5d382
--- /dev/null
+++ b/3rdparty/speex/libspeex/lpc.c
@@ -0,0 +1,201 @@
+/*
+  Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann,
+  Technische Universitaet Berlin
+
+  Any use of this software is permitted provided that this notice is not
+  removed and that neither the authors nor the Technische Universitaet Berlin
+  are deemed to have made any representations as to the suitability of this
+  software for any purpose nor are held responsible for any defects of
+  this software.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+
+  As a matter of courtesy, the authors request to be informed about uses
+  this software has found, about bugs in this software, and about any
+  improvements that may be of general interest.
+
+  Berlin, 28.11.1994
+  Jutta Degener
+  Carsten Bormann
+
+
+   Code modified by Jean-Marc Valin
+
+   Speex License:
+
+   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 "lpc.h"
+
+#ifdef BFIN_ASM
+#include "lpc_bfin.h"
+#endif
+
+/* LPC analysis
+ *
+ * The next two functions calculate linear prediction coefficients
+ * and/or the related reflection coefficients from the first P_MAX+1
+ * values of the autocorrelation function.
+ */
+
+/* Invented by N. Levinson in 1947, modified by J. Durbin in 1959.
+ */
+
+/* returns minimum mean square error    */
+spx_word32_t _spx_lpc(
+spx_coef_t       *lpc, /* out: [0...p-1] LPC coefficients      */
+const spx_word16_t *ac,  /* in:  [0...p] autocorrelation values  */
+int          p
+)
+{
+   int i, j;  
+   spx_word16_t r;
+   spx_word16_t error = ac[0];
+
+   if (ac[0] == 0)
+   {
+      for (i = 0; i < p; i++)
+         lpc[i] = 0;
+      return 0;
+   }
+
+   for (i = 0; i < p; i++) {
+
+      /* Sum up this iteration's reflection coefficient */
+      spx_word32_t rr = NEG32(SHL32(EXTEND32(ac[i + 1]),13));
+      for (j = 0; j < i; j++) 
+         rr = SUB32(rr,MULT16_16(lpc[j],ac[i - j]));
+#ifdef FIXED_POINT
+      r = DIV32_16(rr+PSHR32(error,1),ADD16(error,8));
+#else
+      r = rr/(error+.003*ac[0]);
+#endif
+      /*  Update LPC coefficients and total error */
+      lpc[i] = r;
+      for (j = 0; j < i>>1; j++) 
+      {
+         spx_word16_t tmp  = lpc[j];
+         lpc[j]     = MAC16_16_P13(lpc[j],r,lpc[i-1-j]);
+         lpc[i-1-j] = MAC16_16_P13(lpc[i-1-j],r,tmp);
+      }
+      if (i & 1) 
+         lpc[j] = MAC16_16_P13(lpc[j],lpc[j],r);
+
+      error = SUB16(error,MULT16_16_Q13(r,MULT16_16_Q13(error,r)));
+   }
+   return error;
+}
+
+
+#ifdef FIXED_POINT
+
+/* Compute the autocorrelation
+ *                      ,--,
+ *              ac(i) = >  x(n) * x(n-i)  for all n
+ *                      `--'
+ * for lags between 0 and lag-1, and x == 0 outside 0...n-1
+ */
+
+#ifndef OVERRIDE_SPEEX_AUTOCORR
+void _spx_autocorr(
+const spx_word16_t *x,   /*  in: [0...n-1] samples x   */
+spx_word16_t       *ac,  /* out: [0...lag-1] ac values */
+int          lag, 
+int          n
+)
+{
+   spx_word32_t d;
+   int i, j;
+   spx_word32_t ac0=1;
+   int shift, ac_shift;
+   
+   for (j=0;j<n;j++)
+      ac0 = ADD32(ac0,SHR32(MULT16_16(x[j],x[j]),8));
+   ac0 = ADD32(ac0,n);
+   shift = 8;
+   while (shift && ac0<0x40000000)
+   {
+      shift--;
+      ac0 <<= 1;
+   }
+   ac_shift = 18;
+   while (ac_shift && ac0<0x40000000)
+   {
+      ac_shift--;
+      ac0 <<= 1;
+   }
+   
+   
+   for (i=0;i<lag;i++)
+   {
+      d=0;
+      for (j=i;j<n;j++)
+      {
+         d = ADD32(d,SHR32(MULT16_16(x[j],x[j-i]), shift));
+      }
+      
+      ac[i] = SHR32(d, ac_shift);
+   }
+}
+#endif
+
+
+#else
+
+
+
+/* Compute the autocorrelation
+ *                      ,--,
+ *              ac(i) = >  x(n) * x(n-i)  for all n
+ *                      `--'
+ * for lags between 0 and lag-1, and x == 0 outside 0...n-1
+ */
+void _spx_autocorr(
+const spx_word16_t *x,   /*  in: [0...n-1] samples x   */
+float       *ac,  /* out: [0...lag-1] ac values */
+int          lag, 
+int          n
+)
+{
+   float d;
+   int i;
+   while (lag--) 
+   {
+      for (i = lag, d = 0; i < n; i++) 
+         d += x[i] * x[i-lag];
+      ac[lag] = d;
+   }
+   ac[0] += 10;
+}
+
+#endif
+
+
diff --git a/3rdparty/speex/libspeex/lpc.h b/3rdparty/speex/libspeex/lpc.h
new file mode 100644
index 0000000..d64df96
--- /dev/null
+++ b/3rdparty/speex/libspeex/lpc.h
@@ -0,0 +1,53 @@
+/* Copyright (C) 2002 Jean-Marc Valin */
+/**
+   @file lpc.h
+   @brief Functions for LPC (Linear Prediction Coefficients) analysis
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef LPC_H
+#define LPC_H
+
+#include "misc.h"
+
+void _spx_autocorr(
+              const spx_word16_t * x,   /*  in: [0...n-1] samples x   */
+              spx_word16_t *ac,   /* out: [0...lag-1] ac values */
+              int lag, int   n);
+
+spx_word32_t                      /* returns minimum mean square error    */
+_spx_lpc(
+    spx_coef_t       * lpc, /*      [0...p-1] LPC coefficients      */
+    const spx_word16_t * ac,  /*  in: [0...p] autocorrelation values  */
+    int p
+    );
+
+
+#endif
diff --git a/3rdparty/speex/libspeex/lpc_bfin.h b/3rdparty/speex/libspeex/lpc_bfin.h
new file mode 100644
index 0000000..7310ffb
--- /dev/null
+++ b/3rdparty/speex/libspeex/lpc_bfin.h
@@ -0,0 +1,131 @@
+/* Copyright (C) 2005 Analog Devices */
+/**
+   @file lpc_bfin.h
+   @author Jean-Marc Valin 
+   @brief Functions for LPC (Linear Prediction Coefficients) analysis (Blackfin version)
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define OVERRIDE_SPEEX_AUTOCORR
+void _spx_autocorr(
+const spx_word16_t *x,   /*  in: [0...n-1] samples x   */
+spx_word16_t       *ac,  /* out: [0...lag-1] ac values */
+int          lag, 
+int          n
+                  )
+{
+   spx_word32_t d;
+   const spx_word16_t *xs;
+   int i, j;
+   spx_word32_t ac0=1;
+   spx_word32_t ac32[11], *ac32top;
+   int shift, ac_shift;
+   ac32top = ac32+lag-1;
+   int lag_1, N_lag;
+   int nshift;
+   lag_1 = lag-1;
+   N_lag = n-lag_1;
+   for (j=0;j<n;j++)
+      ac0 = ADD32(ac0,SHR32(MULT16_16(x[j],x[j]),8));
+   ac0 = ADD32(ac0,n);
+   shift = 8;
+   while (shift && ac0<0x40000000)
+   {
+      shift--;
+      ac0 <<= 1;
+   }
+   ac_shift = 18;
+   while (ac_shift && ac0<0x40000000)
+   {
+      ac_shift--;
+      ac0 <<= 1;
+   }
+   
+   xs = x+lag-1;
+   nshift = -shift;
+   __asm__ __volatile__ 
+   (
+         "P2 = %0;\n\t"
+         "I0 = P2;\n\t" /* x in I0 */
+         "B0 = P2;\n\t" /* x in B0 */
+         "R0 = %3;\n\t" /* len in R0 */
+         "P3 = %3;\n\t" /* len in R0 */
+         "P4 = %4;\n\t" /* nb_pitch in R0 */
+         "R1 = R0 << 1;\n\t" /* number of bytes in x */
+         "L0 = R1;\n\t"
+         "P0 = %1;\n\t"
+         "P1 = %2;\n\t"
+         "B1 = P1;\n\t"
+         "R4 = %5;\n\t"
+         "L1 = 0;\n\t" /*Disable looping on I1*/
+
+         "r0 = [I0++];\n\t"
+         "R2 = 0;R3=0;"
+         "LOOP pitch%= LC0 = P4 >> 1;\n\t"
+         "LOOP_BEGIN pitch%=;\n\t"
+            "I1 = P0;\n\t"
+            "A1 = A0 = 0;\n\t"
+            "R1 = [I1++];\n\t"
+            "LOOP inner_prod%= LC1 = P3 >> 1;\n\t"
+            "LOOP_BEGIN inner_prod%=;\n\t"
+               "A1 += R0.L*R1.H, A0 += R0.L*R1.L (IS) || R1.L = W[I1++];\n\t"
+               "A1 += R0.H*R1.L, A0 += R0.H*R1.H (IS) || R1.H = W[I1++] || R0 = [I0++];\n\t"
+            "LOOP_END inner_prod%=;\n\t"
+            "A0 = ASHIFT A0 by R4.L;\n\t"
+            "A1 = ASHIFT A1 by R4.L;\n\t"
+   
+            "R2 = A0, R3 = A1;\n\t"
+            "[P1--] = R2;\n\t"
+            "[P1--] = R3;\n\t"
+            "P0 += 4;\n\t"
+         "LOOP_END pitch%=;\n\t"
+   : : "m" (xs), "m" (x), "m" (ac32top), "m" (N_lag), "m" (lag_1), "m" (nshift)
+   : "A0", "A1", "P0", "P1", "P2", "P3", "P4", "R0", "R1", "R2", "R3", "R4", "I0", "I1", "L0", "L1", "B0", "B1", "memory"
+   );
+   d=0;
+   for (j=0;j<n;j++)
+   {
+      d = ADD32(d,SHR32(MULT16_16(x[j],x[j]), shift));
+   }
+   ac32[0] = d;
+   
+   for (i=0;i<lag;i++)
+   {
+      d=0;
+      for (j=i;j<lag_1;j++)
+      {
+         d = ADD32(d,SHR32(MULT16_16(x[j],x[j-i]), shift));
+      }
+      if (i)
+         ac32[i] += d;
+      ac[i] = SHR32(ac32[i], ac_shift);
+   }
+}
+
diff --git a/3rdparty/speex/libspeex/lsp.c b/3rdparty/speex/libspeex/lsp.c
new file mode 100644
index 0000000..a73d883
--- /dev/null
+++ b/3rdparty/speex/libspeex/lsp.c
@@ -0,0 +1,656 @@
+/*---------------------------------------------------------------------------*\
+Original copyright
+	FILE........: lsp.c
+	AUTHOR......: David Rowe
+	DATE CREATED: 24/2/93
+
+Heavily modified by Jean-Marc Valin (c) 2002-2006 (fixed-point, 
+                       optimizations, additional functions, ...)
+
+   This file contains functions for converting Linear Prediction
+   Coefficients (LPC) to Line Spectral Pair (LSP) and back. Note that the
+   LSP coefficients are not in radians format but in the x domain of the
+   unit circle.
+
+   Speex License:
+
+   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.
+*/
+
+/*---------------------------------------------------------------------------*\
+
+  Introduction to Line Spectrum Pairs (LSPs)
+  ------------------------------------------
+
+  LSPs are used to encode the LPC filter coefficients {ak} for
+  transmission over the channel.  LSPs have several properties (like
+  less sensitivity to quantisation noise) that make them superior to
+  direct quantisation of {ak}.
+
+  A(z) is a polynomial of order lpcrdr with {ak} as the coefficients.
+
+  A(z) is transformed to P(z) and Q(z) (using a substitution and some
+  algebra), to obtain something like:
+
+    A(z) = 0.5[P(z)(z+z^-1) + Q(z)(z-z^-1)]  (1)
+
+  As you can imagine A(z) has complex zeros all over the z-plane. P(z)
+  and Q(z) have the very neat property of only having zeros _on_ the
+  unit circle.  So to find them we take a test point z=exp(jw) and
+  evaluate P (exp(jw)) and Q(exp(jw)) using a grid of points between 0
+  and pi.
+
+  The zeros (roots) of P(z) also happen to alternate, which is why we
+  swap coefficients as we find roots.  So the process of finding the
+  LSP frequencies is basically finding the roots of 5th order
+  polynomials.
+
+  The root so P(z) and Q(z) occur in symmetrical pairs at +/-w, hence
+  the name Line Spectrum Pairs (LSPs).
+
+  To convert back to ak we just evaluate (1), "clocking" an impulse
+  thru it lpcrdr times gives us the impulse response of A(z) which is
+  {ak}.
+
+\*---------------------------------------------------------------------------*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include "lsp.h"
+#include "stack_alloc.h"
+#include "math_approx.h"
+
+#ifndef M_PI
+#define M_PI           3.14159265358979323846  /* pi */
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifdef FIXED_POINT
+
+#define FREQ_SCALE 16384
+
+/*#define ANGLE2X(a) (32768*cos(((a)/8192.)))*/
+#define ANGLE2X(a) (SHL16(spx_cos(a),2))
+
+/*#define X2ANGLE(x) (acos(.00006103515625*(x))*LSP_SCALING)*/
+#define X2ANGLE(x) (spx_acos(x))
+
+#ifdef BFIN_ASM
+#include "lsp_bfin.h"
+#endif
+
+#else
+
+/*#define C1 0.99940307
+#define C2 -0.49558072
+#define C3 0.03679168*/
+
+#define FREQ_SCALE 1.
+#define ANGLE2X(a) (spx_cos(a))
+#define X2ANGLE(x) (acos(x))
+
+#endif
+
+
+/*---------------------------------------------------------------------------*\
+
+   FUNCTION....: cheb_poly_eva()
+
+   AUTHOR......: David Rowe
+   DATE CREATED: 24/2/93
+
+   This function evaluates a series of Chebyshev polynomials
+
+\*---------------------------------------------------------------------------*/
+
+#ifdef FIXED_POINT
+
+#ifndef OVERRIDE_CHEB_POLY_EVA
+static inline spx_word32_t cheb_poly_eva(
+  spx_word16_t *coef, /* P or Q coefs in Q13 format               */
+  spx_word16_t     x, /* cos of freq (-1.0 to 1.0) in Q14 format  */
+  int              m, /* LPC order/2                              */
+  char         *stack
+)
+{
+    int i;
+    spx_word16_t b0, b1;
+    spx_word32_t sum;
+
+    /*Prevents overflows*/
+    if (x>16383)
+       x = 16383;
+    if (x<-16383)
+       x = -16383;
+
+    /* Initialise values */
+    b1=16384;
+    b0=x;
+
+    /* Evaluate Chebyshev series formulation usin g iterative approach  */
+    sum = ADD32(EXTEND32(coef[m]), EXTEND32(MULT16_16_P14(coef[m-1],x)));
+    for(i=2;i<=m;i++)
+    {
+       spx_word16_t tmp=b0;
+       b0 = SUB16(MULT16_16_Q13(x,b0), b1);
+       b1 = tmp;
+       sum = ADD32(sum, EXTEND32(MULT16_16_P14(coef[m-i],b0)));
+    }
+    
+    return sum;
+}
+#endif
+
+#else
+
+static float cheb_poly_eva(spx_word32_t *coef, spx_word16_t x, int m, char *stack)
+{
+   int k;
+   float b0, b1, tmp;
+
+   /* Initial conditions */
+   b0=0; /* b_(m+1) */
+   b1=0; /* b_(m+2) */
+
+   x*=2;
+
+   /* Calculate the b_(k) */
+   for(k=m;k>0;k--)
+   {
+      tmp=b0;                           /* tmp holds the previous value of b0 */
+      b0=x*b0-b1+coef[m-k];    /* b0 holds its new value based on b0 and b1 */
+      b1=tmp;                           /* b1 holds the previous value of b0 */
+   }
+
+   return(-b1+.5*x*b0+coef[m]);
+}
+#endif
+
+/*---------------------------------------------------------------------------*\
+
+    FUNCTION....: lpc_to_lsp()
+
+    AUTHOR......: David Rowe
+    DATE CREATED: 24/2/93
+
+    This function converts LPC coefficients to LSP
+    coefficients.
+
+\*---------------------------------------------------------------------------*/
+
+#ifdef FIXED_POINT
+#define SIGN_CHANGE(a,b) (((a)&0x70000000)^((b)&0x70000000)||(b==0))
+#else
+#define SIGN_CHANGE(a,b) (((a)*(b))<0.0)
+#endif
+
+
+int lpc_to_lsp (spx_coef_t *a,int lpcrdr,spx_lsp_t *freq,int nb,spx_word16_t delta, char *stack)
+/*  float *a 		     	lpc coefficients			*/
+/*  int lpcrdr			order of LPC coefficients (10) 		*/
+/*  float *freq 	      	LSP frequencies in the x domain       	*/
+/*  int nb			number of sub-intervals (4) 		*/
+/*  float delta			grid spacing interval (0.02) 		*/
+
+
+{
+    spx_word16_t temp_xr,xl,xr,xm=0;
+    spx_word32_t psuml,psumr,psumm,temp_psumr/*,temp_qsumr*/;
+    int i,j,m,flag,k;
+    VARDECL(spx_word32_t *Q);                 	/* ptrs for memory allocation 		*/
+    VARDECL(spx_word32_t *P);
+    VARDECL(spx_word16_t *Q16);         /* ptrs for memory allocation 		*/
+    VARDECL(spx_word16_t *P16);
+    spx_word32_t *px;                	/* ptrs of respective P'(z) & Q'(z)	*/
+    spx_word32_t *qx;
+    spx_word32_t *p;
+    spx_word32_t *q;
+    spx_word16_t *pt;                	/* ptr used for cheb_poly_eval()
+				whether P' or Q' 			*/
+    int roots=0;              	/* DR 8/2/94: number of roots found 	*/
+    flag = 1;                	/*  program is searching for a root when,
+				1 else has found one 			*/
+    m = lpcrdr/2;            	/* order of P'(z) & Q'(z) polynomials 	*/
+
+    /* Allocate memory space for polynomials */
+    ALLOC(Q, (m+1), spx_word32_t);
+    ALLOC(P, (m+1), spx_word32_t);
+
+    /* determine P'(z)'s and Q'(z)'s coefficients where
+      P'(z) = P(z)/(1 + z^(-1)) and Q'(z) = Q(z)/(1-z^(-1)) */
+
+    px = P;                      /* initialise ptrs 			*/
+    qx = Q;
+    p = px;
+    q = qx;
+
+#ifdef FIXED_POINT
+    *px++ = LPC_SCALING;
+    *qx++ = LPC_SCALING;
+    for(i=0;i<m;i++){
+       *px++ = SUB32(ADD32(EXTEND32(a[i]),EXTEND32(a[lpcrdr-i-1])), *p++);
+       *qx++ = ADD32(SUB32(EXTEND32(a[i]),EXTEND32(a[lpcrdr-i-1])), *q++);
+    }
+    px = P;
+    qx = Q;
+    for(i=0;i<m;i++)
+    {
+       /*if (fabs(*px)>=32768)
+          speex_warning_int("px", *px);
+       if (fabs(*qx)>=32768)
+       speex_warning_int("qx", *qx);*/
+       *px = PSHR32(*px,2);
+       *qx = PSHR32(*qx,2);
+       px++;
+       qx++;
+    }
+    /* The reason for this lies in the way cheb_poly_eva() is implemented for fixed-point */
+    P[m] = PSHR32(P[m],3);
+    Q[m] = PSHR32(Q[m],3);
+#else
+    *px++ = LPC_SCALING;
+    *qx++ = LPC_SCALING;
+    for(i=0;i<m;i++){
+       *px++ = (a[i]+a[lpcrdr-1-i]) - *p++;
+       *qx++ = (a[i]-a[lpcrdr-1-i]) + *q++;
+    }
+    px = P;
+    qx = Q;
+    for(i=0;i<m;i++){
+       *px = 2**px;
+       *qx = 2**qx;
+       px++;
+       qx++;
+    }
+#endif
+
+    px = P;             	/* re-initialise ptrs 			*/
+    qx = Q;
+
+    /* now that we have computed P and Q convert to 16 bits to
+       speed up cheb_poly_eval */
+
+    ALLOC(P16, m+1, spx_word16_t);
+    ALLOC(Q16, m+1, spx_word16_t);
+
+    for (i=0;i<m+1;i++)
+    {
+       P16[i] = P[i];
+       Q16[i] = Q[i];
+    }
+
+    /* Search for a zero in P'(z) polynomial first and then alternate to Q'(z).
+    Keep alternating between the two polynomials as each zero is found 	*/
+
+    xr = 0;             	/* initialise xr to zero 		*/
+    xl = FREQ_SCALE;               	/* start at point xl = 1 		*/
+
+    for(j=0;j<lpcrdr;j++){
+	if(j&1)            	/* determines whether P' or Q' is eval. */
+	    pt = Q16;
+	else
+	    pt = P16;
+
+	psuml = cheb_poly_eva(pt,xl,m,stack);	/* evals poly. at xl 	*/
+	flag = 1;
+	while(flag && (xr >= -FREQ_SCALE)){
+           spx_word16_t dd;
+           /* Modified by JMV to provide smaller steps around x=+-1 */
+#ifdef FIXED_POINT
+           dd = MULT16_16_Q15(delta,SUB16(FREQ_SCALE, MULT16_16_Q14(MULT16_16_Q14(xl,xl),14000)));
+           if (psuml<512 && psuml>-512)
+              dd = PSHR16(dd,1);
+#else
+           dd=delta*(1-.9*xl*xl);
+           if (fabs(psuml)<.2)
+              dd *= .5;
+#endif
+           xr = SUB16(xl, dd);                        	/* interval spacing 	*/
+	    psumr = cheb_poly_eva(pt,xr,m,stack);/* poly(xl-delta_x) 	*/
+	    temp_psumr = psumr;
+	    temp_xr = xr;
+
+    /* if no sign change increment xr and re-evaluate poly(xr). Repeat til
+    sign change.
+    if a sign change has occurred the interval is bisected and then
+    checked again for a sign change which determines in which
+    interval the zero lies in.
+    If there is no sign change between poly(xm) and poly(xl) set interval
+    between xm and xr else set interval between xl and xr and repeat till
+    root is located within the specified limits 			*/
+
+	    if(SIGN_CHANGE(psumr,psuml))
+            {
+		roots++;
+
+		psumm=psuml;
+		for(k=0;k<=nb;k++){
+#ifdef FIXED_POINT
+		    xm = ADD16(PSHR16(xl,1),PSHR16(xr,1));        	/* bisect the interval 	*/
+#else
+                    xm = .5*(xl+xr);        	/* bisect the interval 	*/
+#endif
+		    psumm=cheb_poly_eva(pt,xm,m,stack);
+		    /*if(psumm*psuml>0.)*/
+		    if(!SIGN_CHANGE(psumm,psuml))
+                    {
+			psuml=psumm;
+			xl=xm;
+		    } else {
+			psumr=psumm;
+			xr=xm;
+		    }
+		}
+
+	       /* once zero is found, reset initial interval to xr 	*/
+	       freq[j] = X2ANGLE(xm);
+	       xl = xm;
+	       flag = 0;       		/* reset flag for next search 	*/
+	    }
+	    else{
+		psuml=temp_psumr;
+		xl=temp_xr;
+	    }
+	}
+    }
+    return(roots);
+}
+
+/*---------------------------------------------------------------------------*\
+
+	FUNCTION....: lsp_to_lpc()
+
+	AUTHOR......: David Rowe
+	DATE CREATED: 24/2/93
+
+        Converts LSP coefficients to LPC coefficients.
+
+\*---------------------------------------------------------------------------*/
+
+#ifdef FIXED_POINT
+
+void lsp_to_lpc(spx_lsp_t *freq,spx_coef_t *ak,int lpcrdr, char *stack)
+/*  float *freq 	array of LSP frequencies in the x domain	*/
+/*  float *ak 		array of LPC coefficients 			*/
+/*  int lpcrdr  	order of LPC coefficients 			*/
+{
+    int i,j;
+    spx_word32_t xout1,xout2,xin;
+    spx_word32_t mult, a;
+    VARDECL(spx_word16_t *freqn);
+    VARDECL(spx_word32_t **xp);
+    VARDECL(spx_word32_t *xpmem);
+    VARDECL(spx_word32_t **xq);
+    VARDECL(spx_word32_t *xqmem);
+    int m = lpcrdr>>1;
+
+    /* 
+    
+       Reconstruct P(z) and Q(z) by cascading second order polynomials
+       in form 1 - 2cos(w)z(-1) + z(-2), where w is the LSP frequency.
+       In the time domain this is:
+
+       y(n) = x(n) - 2cos(w)x(n-1) + x(n-2)
+    
+       This is what the ALLOCS below are trying to do:
+
+         int xp[m+1][lpcrdr+1+2]; // P matrix in QIMP
+         int xq[m+1][lpcrdr+1+2]; // Q matrix in QIMP
+
+       These matrices store the output of each stage on each row.  The
+       final (m-th) row has the output of the final (m-th) cascaded
+       2nd order filter.  The first row is the impulse input to the
+       system (not written as it is known).
+
+       The version below takes advantage of the fact that a lot of the
+       outputs are zero or known, for example if we put an inpulse
+       into the first section the "clock" it 10 times only the first 3
+       outputs samples are non-zero (it's an FIR filter).
+    */
+
+    ALLOC(xp, (m+1), spx_word32_t*);
+    ALLOC(xpmem, (m+1)*(lpcrdr+1+2), spx_word32_t);
+
+    ALLOC(xq, (m+1), spx_word32_t*);
+    ALLOC(xqmem, (m+1)*(lpcrdr+1+2), spx_word32_t);
+    
+    for(i=0; i<=m; i++) {
+      xp[i] = xpmem + i*(lpcrdr+1+2);
+      xq[i] = xqmem + i*(lpcrdr+1+2);
+    }
+
+    /* work out 2cos terms in Q14 */
+
+    ALLOC(freqn, lpcrdr, spx_word16_t);
+    for (i=0;i<lpcrdr;i++) 
+       freqn[i] = ANGLE2X(freq[i]);
+
+    #define QIMP  21   /* scaling for impulse */
+
+    xin = SHL32(EXTEND32(1), (QIMP-1)); /* 0.5 in QIMP format */
+   
+    /* first col and last non-zero values of each row are trivial */
+    
+    for(i=0;i<=m;i++) {
+     xp[i][1] = 0;
+     xp[i][2] = xin;
+     xp[i][2+2*i] = xin;
+     xq[i][1] = 0;
+     xq[i][2] = xin;
+     xq[i][2+2*i] = xin;
+    }
+
+    /* 2nd row (first output row) is trivial */
+
+    xp[1][3] = -MULT16_32_Q14(freqn[0],xp[0][2]);
+    xq[1][3] = -MULT16_32_Q14(freqn[1],xq[0][2]);
+
+    xout1 = xout2 = 0;
+
+    /* now generate remaining rows */
+
+    for(i=1;i<m;i++) {
+
+      for(j=1;j<2*(i+1)-1;j++) {
+	mult = MULT16_32_Q14(freqn[2*i],xp[i][j+1]);
+	xp[i+1][j+2] = ADD32(SUB32(xp[i][j+2], mult), xp[i][j]);
+	mult = MULT16_32_Q14(freqn[2*i+1],xq[i][j+1]);
+	xq[i+1][j+2] = ADD32(SUB32(xq[i][j+2], mult), xq[i][j]);
+      }
+
+      /* for last col xp[i][j+2] = xq[i][j+2] = 0 */
+
+      mult = MULT16_32_Q14(freqn[2*i],xp[i][j+1]);
+      xp[i+1][j+2] = SUB32(xp[i][j], mult);
+      mult = MULT16_32_Q14(freqn[2*i+1],xq[i][j+1]);
+      xq[i+1][j+2] = SUB32(xq[i][j], mult);
+    }
+
+    /* process last row to extra a{k} */
+
+    for(j=1;j<=lpcrdr;j++) {
+      int shift = QIMP-13;
+
+      /* final filter sections */
+      a = PSHR32(xp[m][j+2] + xout1 + xq[m][j+2] - xout2, shift); 
+      xout1 = xp[m][j+2];
+      xout2 = xq[m][j+2];
+      
+      /* hard limit ak's to +/- 32767 */
+
+      if (a < -32767) a = -32767;
+      if (a > 32767) a = 32767;
+      ak[j-1] = (short)a;
+     
+    }
+
+}
+
+#else
+
+void lsp_to_lpc(spx_lsp_t *freq,spx_coef_t *ak,int lpcrdr, char *stack)
+/*  float *freq 	array of LSP frequencies in the x domain	*/
+/*  float *ak 		array of LPC coefficients 			*/
+/*  int lpcrdr  	order of LPC coefficients 			*/
+
+
+{
+    int i,j;
+    float xout1,xout2,xin1,xin2;
+    VARDECL(float *Wp);
+    float *pw,*n1,*n2,*n3,*n4=NULL;
+    VARDECL(float *x_freq);
+    int m = lpcrdr>>1;
+
+    ALLOC(Wp, 4*m+2, float);
+    pw = Wp;
+
+    /* initialise contents of array */
+
+    for(i=0;i<=4*m+1;i++){       	/* set contents of buffer to 0 */
+	*pw++ = 0.0;
+    }
+
+    /* Set pointers up */
+
+    pw = Wp;
+    xin1 = 1.0;
+    xin2 = 1.0;
+
+    ALLOC(x_freq, lpcrdr, float);
+    for (i=0;i<lpcrdr;i++)
+       x_freq[i] = ANGLE2X(freq[i]);
+
+    /* reconstruct P(z) and Q(z) by  cascading second order
+      polynomials in form 1 - 2xz(-1) +z(-2), where x is the
+      LSP coefficient */
+
+    for(j=0;j<=lpcrdr;j++){
+       int i2=0;
+	for(i=0;i<m;i++,i2+=2){
+	    n1 = pw+(i*4);
+	    n2 = n1 + 1;
+	    n3 = n2 + 1;
+	    n4 = n3 + 1;
+	    xout1 = xin1 - 2.f*x_freq[i2] * *n1 + *n2;
+	    xout2 = xin2 - 2.f*x_freq[i2+1] * *n3 + *n4;
+	    *n2 = *n1;
+	    *n4 = *n3;
+	    *n1 = xin1;
+	    *n3 = xin2;
+	    xin1 = xout1;
+	    xin2 = xout2;
+	}
+	xout1 = xin1 + *(n4+1);
+	xout2 = xin2 - *(n4+2);
+	if (j>0)
+	   ak[j-1] = (xout1 + xout2)*0.5f;
+	*(n4+1) = xin1;
+	*(n4+2) = xin2;
+
+	xin1 = 0.0;
+	xin2 = 0.0;
+    }
+
+}
+#endif
+
+
+#ifdef FIXED_POINT
+
+/*Makes sure the LSPs are stable*/
+void lsp_enforce_margin(spx_lsp_t *lsp, int len, spx_word16_t margin)
+{
+   int i;
+   spx_word16_t m = margin;
+   spx_word16_t m2 = 25736-margin;
+  
+   if (lsp[0]<m)
+      lsp[0]=m;
+   if (lsp[len-1]>m2)
+      lsp[len-1]=m2;
+   for (i=1;i<len-1;i++)
+   {
+      if (lsp[i]<lsp[i-1]+m)
+         lsp[i]=lsp[i-1]+m;
+
+      if (lsp[i]>lsp[i+1]-m)
+         lsp[i]= SHR16(lsp[i],1) + SHR16(lsp[i+1]-m,1);
+   }
+}
+
+
+void lsp_interpolate(spx_lsp_t *old_lsp, spx_lsp_t *new_lsp, spx_lsp_t *interp_lsp, int len, int subframe, int nb_subframes)
+{
+   int i;
+   spx_word16_t tmp = DIV32_16(SHL32(EXTEND32(1 + subframe),14),nb_subframes);
+   spx_word16_t tmp2 = 16384-tmp;
+   for (i=0;i<len;i++)
+   {
+      interp_lsp[i] = MULT16_16_P14(tmp2,old_lsp[i]) + MULT16_16_P14(tmp,new_lsp[i]);
+   }
+}
+
+#else
+
+/*Makes sure the LSPs are stable*/
+void lsp_enforce_margin(spx_lsp_t *lsp, int len, spx_word16_t margin)
+{
+   int i;
+   if (lsp[0]<LSP_SCALING*margin)
+      lsp[0]=LSP_SCALING*margin;
+   if (lsp[len-1]>LSP_SCALING*(M_PI-margin))
+      lsp[len-1]=LSP_SCALING*(M_PI-margin);
+   for (i=1;i<len-1;i++)
+   {
+      if (lsp[i]<lsp[i-1]+LSP_SCALING*margin)
+         lsp[i]=lsp[i-1]+LSP_SCALING*margin;
+
+      if (lsp[i]>lsp[i+1]-LSP_SCALING*margin)
+         lsp[i]= .5f* (lsp[i] + lsp[i+1]-LSP_SCALING*margin);
+   }
+}
+
+
+void lsp_interpolate(spx_lsp_t *old_lsp, spx_lsp_t *new_lsp, spx_lsp_t *interp_lsp, int len, int subframe, int nb_subframes)
+{
+   int i;
+   float tmp = (1.0f + subframe)/nb_subframes;
+   for (i=0;i<len;i++)
+   {
+      interp_lsp[i] = (1-tmp)*old_lsp[i] + tmp*new_lsp[i];
+   }
+}
+
+#endif
diff --git a/3rdparty/speex/libspeex/lsp.h b/3rdparty/speex/libspeex/lsp.h
new file mode 100644
index 0000000..6266f42
--- /dev/null
+++ b/3rdparty/speex/libspeex/lsp.h
@@ -0,0 +1,64 @@
+/*---------------------------------------------------------------------------*\
+Original Copyright
+	FILE........: AK2LSPD.H
+	TYPE........: Turbo C header file
+	COMPANY.....: Voicetronix
+	AUTHOR......: James Whitehall
+	DATE CREATED: 21/11/95
+
+Modified by Jean-Marc Valin
+
+    This file contains functions for converting Linear Prediction
+    Coefficients (LPC) to Line Spectral Pair (LSP) and back. Note that the
+    LSP coefficients are not in radians format but in the x domain of the
+    unit circle.
+
+\*---------------------------------------------------------------------------*/
+/**
+   @file lsp.h
+   @brief Line Spectral Pair (LSP) functions.
+*/
+/* Speex License:
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __AK2LSPD__
+#define __AK2LSPD__
+
+#include "misc.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);
+
+/*Added by JMV*/
+void lsp_enforce_margin(spx_lsp_t *lsp, int len, spx_word16_t margin);
+
+void lsp_interpolate(spx_lsp_t *old_lsp, spx_lsp_t *new_lsp, spx_lsp_t *interp_lsp, int len, int subframe, int nb_subframes);
+
+#endif	/* __AK2LSPD__ */
diff --git a/3rdparty/speex/libspeex/lsp_bfin.h b/3rdparty/speex/libspeex/lsp_bfin.h
new file mode 100644
index 0000000..20e5052
--- /dev/null
+++ b/3rdparty/speex/libspeex/lsp_bfin.h
@@ -0,0 +1,89 @@
+/* Copyright (C) 2006 David Rowe */
+/**
+   @file lsp_bfin.h
+   @author David Rowe
+   @brief LSP routines optimised for the Blackfin
+*/
+/*
+   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.
+*/
+
+#define OVERRIDE_CHEB_POLY_EVA
+#ifdef OVERRIDE_CHEB_POLY_EVA
+static inline spx_word32_t cheb_poly_eva(
+  spx_word16_t *coef, /* P or Q coefs in Q13 format               */
+  spx_word16_t     x, /* cos of freq (-1.0 to 1.0) in Q14 format  */
+  int              m, /* LPC order/2                              */
+  char         *stack
+)
+{
+    spx_word32_t sum;
+
+   __asm__ __volatile__
+     (
+      "P0 = %2;\n\t"           /* P0: coef[m], coef[m-1],..., coef[0] */
+      "R4 = 8192;\n\t"         /* R4: rounding constant               */
+      "R2 = %1;\n\t"           /* R2: x  */
+
+      "R5 = -16383;\n\t"
+      "R2 = MAX(R2,R5);\n\t"
+      "R5 = 16383;\n\t"
+      "R2 = MIN(R2,R5);\n\t"
+
+      "R3 = W[P0--] (X);\n\t"  /* R3: sum */
+      "R5 = W[P0--] (X);\n\t"
+      "R5 = R5.L * R2.L (IS);\n\t"
+      "R5 = R5 + R4;\n\t"
+      "R5 >>>= 14;\n\t"
+      "R3 = R3 + R5;\n\t" 
+      
+      "R0 = R2;\n\t"           /* R0: b0 */
+      "R1 = 16384;\n\t"        /* R1: b1 */
+      "LOOP cpe%= LC0 = %3;\n\t"
+      "LOOP_BEGIN cpe%=;\n\t"
+        "P1 = R0;\n\t" 
+        "R0 = R2.L * R0.L (IS) || R5 = W[P0--] (X);\n\t"
+        "R0 >>>= 13;\n\t"
+        "R0 = R0 - R1;\n\t"
+        "R1 = P1;\n\t"
+        "R5 = R5.L * R0.L (IS);\n\t"
+        "R5 = R5 + R4;\n\t"
+        "R5 >>>= 14;\n\t"
+        "R3 = R3 + R5;\n\t"
+      "LOOP_END cpe%=;\n\t"
+      "%0 = R3;\n\t"
+      : "=&d" (sum)
+      : "a" (x), "a" (&coef[m]), "a" (m-1)
+      : "R0", "R1", "R3", "R2", "R4", "R5", "P0", "P1"
+      );
+    return sum;
+}
+#endif
+
+
+
diff --git a/3rdparty/speex/libspeex/lsp_tables_nb.c b/3rdparty/speex/libspeex/lsp_tables_nb.c
new file mode 100644
index 0000000..16f2e1b
--- /dev/null
+++ b/3rdparty/speex/libspeex/lsp_tables_nb.c
@@ -0,0 +1,360 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: lsp_tables_nb.c
+   Codebooks for LSPs in narrowband CELP mode
+  
+   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.
+*/
+
+const signed char cdbk_nb[640]={
+30,19,38,34,40,32,46,43,58,43,
+5,-18,-25,-40,-33,-55,-52,20,34,28,
+-20,-63,-97,-92,61,53,47,49,53,75,
+-14,-53,-77,-79,0,-3,-5,19,22,26,
+-9,-53,-55,66,90,72,85,68,74,52,
+-4,-41,-58,-31,-18,-31,27,32,30,18,
+24,3,8,5,-12,-3,26,28,74,63,
+-2,-39,-67,-77,-106,-74,59,59,73,65,
+44,40,71,72,82,83,98,88,89,60,
+-6,-31,-47,-48,-13,-39,-9,7,2,79,
+-1,-39,-60,-17,87,81,65,50,45,19,
+-21,-67,-91,-87,-41,-50,7,18,39,74,
+10,-31,-28,39,24,13,23,5,56,45,
+29,10,-5,-13,-11,-35,-18,-8,-10,-8,
+-25,-71,-77,-21,2,16,50,63,87,87,
+5,-32,-40,-51,-68,0,12,6,54,34,
+5,-12,32,52,68,64,69,59,65,45,
+14,-16,-31,-40,-65,-67,41,49,47,37,
+-11,-52,-75,-84,-4,57,48,42,42,33,
+-11,-51,-68,-6,13,0,8,-8,26,32,
+-23,-53,0,36,56,76,97,105,111,97,
+-1,-28,-39,-40,-43,-54,-44,-40,-18,35,
+16,-20,-19,-28,-42,29,47,38,74,45,
+3,-29,-48,-62,-80,-104,-33,56,59,59,
+10,17,46,72,84,101,117,123,123,106,
+-7,-33,-49,-51,-70,-67,-27,-31,70,67,
+-16,-62,-85,-20,82,71,86,80,85,74,
+-19,-58,-75,-45,-29,-33,-18,-25,45,57,
+-12,-42,-5,12,28,36,52,64,81,82,
+13,-9,-27,-28,22,3,2,22,26,6,
+-6,-44,-51,2,15,10,48,43,49,34,
+-19,-62,-84,-89,-102,-24,8,17,61,68,
+39,24,23,19,16,-5,12,15,27,15,
+-8,-44,-49,-60,-18,-32,-28,52,54,62,
+-8,-48,-77,-70,66,101,83,63,61,37,
+-12,-50,-75,-64,33,17,13,25,15,77,
+1,-42,-29,72,64,46,49,31,61,44,
+-8,-47,-54,-46,-30,19,20,-1,-16,0,
+16,-12,-18,-9,-26,-27,-10,-22,53,45,
+-10,-47,-75,-82,-105,-109,8,25,49,77,
+50,65,114,117,124,118,115,96,90,61,
+-9,-45,-63,-60,-75,-57,8,11,20,29,
+0,-35,-49,-43,40,47,35,40,55,38,
+-24,-76,-103,-112,-27,3,23,34,52,75,
+8,-29,-43,12,63,38,35,29,24,8,
+25,11,1,-15,-18,-43,-7,37,40,21,
+-20,-56,-19,-19,-4,-2,11,29,51,63,
+-2,-44,-62,-75,-89,30,57,51,74,51,
+50,46,68,64,65,52,63,55,65,43,
+18,-9,-26,-35,-55,-69,3,6,8,17,
+-15,-61,-86,-97,1,86,93,74,78,67,
+-1,-38,-66,-48,48,39,29,25,17,-1,
+13,13,29,39,50,51,69,82,97,98,
+-2,-36,-46,-27,-16,-30,-13,-4,-7,-4,
+25,-5,-11,-6,-25,-21,33,12,31,29,
+-8,-38,-52,-63,-68,-89,-33,-1,10,74,
+-2,-15,59,91,105,105,101,87,84,62,
+-7,-33,-50,-35,-54,-47,25,17,82,81,
+-13,-56,-83,21,58,31,42,25,72,65,
+-24,-66,-91,-56,9,-2,21,10,69,75,
+2,-24,11,22,25,28,38,34,48,33,
+7,-29,-26,17,15,-1,14,0,-2,0,
+-6,-41,-67,6,-2,-9,19,2,85,74,
+-22,-67,-84,-71,-50,3,11,-9,2,62};
+
+const signed char cdbk_nb_low1[320]={
+-34,-52,-15,45,2,
+23,21,52,24,-33,
+-9,-1,9,-44,-41,
+-13,-17,44,22,-17,
+-6,-4,-1,22,38,
+26,16,2,50,27,
+-35,-34,-9,-41,6,
+0,-16,-34,51,8,
+-14,-31,-49,15,-33,
+45,49,33,-11,-37,
+-62,-54,45,11,-5,
+-72,11,-1,-12,-11,
+24,27,-11,-43,46,
+43,33,-12,-9,-1,
+1,-4,-23,-57,-71,
+11,8,16,17,-8,
+-20,-31,-41,53,48,
+-16,3,65,-24,-8,
+-23,-32,-37,-32,-49,
+-10,-17,6,38,5,
+-9,-17,-46,8,52,
+3,6,45,40,39,
+-7,-6,-34,-74,31,
+8,1,-16,43,68,
+-11,-19,-31,4,6,
+0,-6,-17,-16,-38,
+-16,-30,2,9,-39,
+-16,-1,43,-10,48,
+3,3,-16,-31,-3,
+62,68,43,13,3,
+-10,8,20,-56,12,
+12,-2,-18,22,-15,
+-40,-36,1,7,41,
+0,1,46,-6,-62,
+-4,-12,-2,-11,-83,
+-13,-2,91,33,-10,
+0,4,-11,-16,79,
+32,37,14,9,51,
+-21,-28,-56,-34,0,
+21,9,-26,11,28,
+-42,-54,-23,-2,-15,
+31,30,8,-39,-66,
+-39,-36,31,-28,-40,
+-46,35,40,22,24,
+33,48,23,-34,14,
+40,32,17,27,-3,
+25,26,-13,-61,-17,
+11,4,31,60,-6,
+-26,-41,-64,13,16,
+-26,54,31,-11,-23,
+-9,-11,-34,-71,-21,
+-34,-35,55,50,29,
+-22,-27,-50,-38,57,
+33,42,57,48,26,
+11,0,-49,-31,26,
+-4,-14,5,78,37,
+17,0,-49,-12,-23,
+26,14,2,2,-43,
+-17,-12,10,-8,-4,
+8,18,12,-6,20,
+-12,-6,-13,-25,34,
+15,40,49,7,8,
+13,20,20,-19,-22,
+-2,-8,2,51,-51};
+
+const signed char cdbk_nb_low2[320]={
+-6,53,-21,-24,4,
+26,17,-4,-37,25,
+17,-36,-13,31,3,
+-6,27,15,-10,31,
+28,26,-10,-10,-40,
+16,-7,15,13,41,
+-9,0,-4,50,-6,
+-7,14,38,22,0,
+-48,2,1,-13,-19,
+32,-3,-60,11,-17,
+-1,-24,-34,-1,35,
+-5,-27,28,44,13,
+25,15,42,-11,15,
+51,35,-36,20,8,
+-4,-12,-29,19,-47,
+49,-15,-4,16,-29,
+-39,14,-30,4,25,
+-9,-5,-51,-14,-3,
+-40,-32,38,5,-9,
+-8,-4,-1,-22,71,
+-3,14,26,-18,-22,
+24,-41,-25,-24,6,
+23,19,-10,39,-26,
+-27,65,45,2,-7,
+-26,-8,22,-12,16,
+15,16,-35,-5,33,
+-21,-8,0,23,33,
+34,6,21,36,6,
+-7,-22,8,-37,-14,
+31,38,11,-4,-3,
+-39,-32,-8,32,-23,
+-6,-12,16,20,-28,
+-4,23,13,-52,-1,
+22,6,-33,-40,-6,
+4,-62,13,5,-26,
+35,39,11,2,57,
+-11,9,-20,-28,-33,
+52,-5,-6,-2,22,
+-14,-16,-48,35,1,
+-58,20,13,33,-1,
+-74,56,-18,-22,-31,
+12,6,-14,4,-2,
+-9,-47,10,-3,29,
+-17,-5,61,14,47,
+-12,2,72,-39,-17,
+92,64,-53,-51,-15,
+-30,-38,-41,-29,-28,
+27,9,36,9,-35,
+-42,81,-21,20,25,
+-16,-5,-17,-35,21,
+15,-28,48,2,-2,
+9,-19,29,-40,30,
+-18,-18,18,-16,-57,
+15,-20,-12,-15,-37,
+-15,33,-39,21,-22,
+-13,35,11,13,-38,
+-63,29,23,-27,32,
+18,3,-26,42,33,
+-64,-66,-17,16,56,
+2,36,3,31,21,
+-41,-39,8,-57,14,
+37,-2,19,-36,-19,
+-23,-29,-16,1,-3,
+-8,-10,31,64,-65};
+
+const signed char cdbk_nb_high1[320]={
+-26,-8,29,21,4,
+19,-39,33,-7,-36,
+56,54,48,40,29,
+-4,-24,-42,-66,-43,
+-60,19,-2,37,41,
+-10,-37,-60,-64,18,
+-22,77,73,40,25,
+4,19,-19,-66,-2,
+11,5,21,14,26,
+-25,-86,-4,18,1,
+26,-37,10,37,-1,
+24,-12,-59,-11,20,
+-6,34,-16,-16,42,
+19,-28,-51,53,32,
+4,10,62,21,-12,
+-34,27,4,-48,-48,
+-50,-49,31,-7,-21,
+-42,-25,-4,-43,-22,
+59,2,27,12,-9,
+-6,-16,-8,-32,-58,
+-16,-29,-5,41,23,
+-30,-33,-46,-13,-10,
+-38,52,52,1,-17,
+-9,10,26,-25,-6,
+33,-20,53,55,25,
+-32,-5,-42,23,21,
+66,5,-28,20,9,
+75,29,-7,-42,-39,
+15,3,-23,21,6,
+11,1,-29,14,63,
+10,54,26,-24,-51,
+-49,7,-23,-51,15,
+-66,1,60,25,10,
+0,-30,-4,-15,17,
+19,59,40,4,-5,
+33,6,-22,-58,-70,
+-5,23,-6,60,44,
+-29,-16,-47,-29,52,
+-19,50,28,16,35,
+31,36,0,-21,6,
+21,27,22,42,7,
+-66,-40,-8,7,19,
+46,0,-4,60,36,
+45,-7,-29,-6,-32,
+-39,2,6,-9,33,
+20,-51,-34,18,-6,
+19,6,11,5,-19,
+-29,-2,42,-11,-45,
+-21,-55,57,37,2,
+-14,-67,-16,-27,-38,
+69,48,19,2,-17,
+20,-20,-16,-34,-17,
+-25,-61,10,73,45,
+16,-40,-64,-17,-29,
+-22,56,17,-39,8,
+-11,8,-25,-18,-13,
+-19,8,54,57,36,
+-17,-26,-4,6,-21,
+40,42,-4,20,31,
+53,10,-34,-53,31,
+-17,35,0,15,-6,
+-20,-63,-73,22,25,
+29,17,8,-29,-39,
+-69,18,15,-15,-5};
+
+const signed char cdbk_nb_high2[320]={
+11,47,16,-9,-46,
+-32,26,-64,34,-5,
+38,-7,47,20,2,
+-73,-99,-3,-45,20,
+70,-52,15,-6,-7,
+-82,31,21,47,51,
+39,-3,9,0,-41,
+-7,-15,-54,2,0,
+27,-31,9,-45,-22,
+-38,-24,-24,8,-33,
+23,5,50,-36,-17,
+-18,-51,-2,13,19,
+43,12,-15,-12,61,
+38,38,7,13,0,
+6,-1,3,62,9,
+27,22,-33,38,-35,
+-9,30,-43,-9,-32,
+-1,4,-4,1,-5,
+-11,-8,38,31,11,
+-10,-42,-21,-37,1,
+43,15,-13,-35,-19,
+-18,15,23,-26,59,
+1,-21,53,8,-41,
+-50,-14,-28,4,21,
+25,-28,-40,5,-40,
+-41,4,51,-33,-8,
+-8,1,17,-60,12,
+25,-41,17,34,43,
+19,45,7,-37,24,
+-15,56,-2,35,-10,
+48,4,-47,-2,5,
+-5,-54,5,-3,-33,
+-10,30,-2,-44,-24,
+-38,9,-9,42,4,
+6,-56,44,-16,9,
+-40,-26,18,-20,10,
+28,-41,-21,-4,13,
+-18,32,-30,-3,37,
+15,22,28,50,-40,
+3,-29,-64,7,51,
+-19,-11,17,-27,-40,
+-64,24,-12,-7,-27,
+3,37,48,-1,2,
+-9,-38,-34,46,1,
+27,-6,19,-13,26,
+10,34,20,25,40,
+50,-6,-7,30,9,
+-24,0,-23,71,-61,
+22,58,-34,-4,2,
+-49,-33,25,30,-8,
+-6,-16,77,2,38,
+-8,-35,-6,-30,56,
+78,31,33,-20,13,
+-39,20,22,4,21,
+-8,4,-6,10,-83,
+-41,9,-25,-43,15,
+-7,-12,-34,-39,-37,
+-33,19,30,16,-33,
+42,-25,25,-68,44,
+-15,-11,-4,23,50,
+14,4,-39,-43,20,
+-30,60,9,-20,7,
+16,19,-33,37,29,
+16,-35,7,38,-27};
diff --git a/3rdparty/speex/libspeex/ltp.c b/3rdparty/speex/libspeex/ltp.c
new file mode 100644
index 0000000..fa77da2
--- /dev/null
+++ b/3rdparty/speex/libspeex/ltp.c
@@ -0,0 +1,846 @@
+/* Copyright (C) 2002-2006 Jean-Marc Valin 
+   File: ltp.c
+   Long-Term Prediction functions
+
+   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 <math.h>
+#include "ltp.h"
+#include "stack_alloc.h"
+#include "filters.h"
+#include <speex/speex_bits.h>
+#include "math_approx.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+
+#ifdef _USE_SSE
+#include "ltp_sse.h"
+#elif defined (ARM4_ASM) || defined(ARM5E_ASM)
+#include "ltp_arm4.h"
+#elif defined (BFIN_ASM)
+#include "ltp_bfin.h"
+#endif
+
+#ifndef OVERRIDE_INNER_PROD
+spx_word32_t inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len)
+{
+   spx_word32_t sum=0;
+   len >>= 2;
+   while(len--)
+   {
+      spx_word32_t part=0;
+      part = MAC16_16(part,*x++,*y++);
+      part = MAC16_16(part,*x++,*y++);
+      part = MAC16_16(part,*x++,*y++);
+      part = MAC16_16(part,*x++,*y++);
+      /* HINT: If you had a 40-bit accumulator, you could shift only at the end */
+      sum = ADD32(sum,SHR32(part,6));
+   }
+   return sum;
+}
+#endif
+
+#ifndef OVERRIDE_PITCH_XCORR
+#if 0 /* HINT: Enable this for machines with enough registers (i.e. not x86) */
+void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack)
+{
+   int i,j;
+   for (i=0;i<nb_pitch;i+=4)
+   {
+      /* Compute correlation*/
+      /*corr[nb_pitch-1-i]=inner_prod(x, _y+i, len);*/
+      spx_word32_t sum1=0;
+      spx_word32_t sum2=0;
+      spx_word32_t sum3=0;
+      spx_word32_t sum4=0;
+      const spx_word16_t *y = _y+i;
+      const spx_word16_t *x = _x;
+      spx_word16_t y0, y1, y2, y3;
+      /*y0=y[0];y1=y[1];y2=y[2];y3=y[3];*/
+      y0=*y++;
+      y1=*y++;
+      y2=*y++;
+      y3=*y++;
+      for (j=0;j<len;j+=4)
+      {
+         spx_word32_t part1;
+         spx_word32_t part2;
+         spx_word32_t part3;
+         spx_word32_t part4;
+         part1 = MULT16_16(*x,y0);
+         part2 = MULT16_16(*x,y1);
+         part3 = MULT16_16(*x,y2);
+         part4 = MULT16_16(*x,y3);
+         x++;
+         y0=*y++;
+         part1 = MAC16_16(part1,*x,y1);
+         part2 = MAC16_16(part2,*x,y2);
+         part3 = MAC16_16(part3,*x,y3);
+         part4 = MAC16_16(part4,*x,y0);
+         x++;
+         y1=*y++;
+         part1 = MAC16_16(part1,*x,y2);
+         part2 = MAC16_16(part2,*x,y3);
+         part3 = MAC16_16(part3,*x,y0);
+         part4 = MAC16_16(part4,*x,y1);
+         x++;
+         y2=*y++;
+         part1 = MAC16_16(part1,*x,y3);
+         part2 = MAC16_16(part2,*x,y0);
+         part3 = MAC16_16(part3,*x,y1);
+         part4 = MAC16_16(part4,*x,y2);
+         x++;
+         y3=*y++;
+         
+         sum1 = ADD32(sum1,SHR32(part1,6));
+         sum2 = ADD32(sum2,SHR32(part2,6));
+         sum3 = ADD32(sum3,SHR32(part3,6));
+         sum4 = ADD32(sum4,SHR32(part4,6));
+      }
+      corr[nb_pitch-1-i]=sum1;
+      corr[nb_pitch-2-i]=sum2;
+      corr[nb_pitch-3-i]=sum3;
+      corr[nb_pitch-4-i]=sum4;
+   }
+
+}
+#else
+void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack)
+{
+   int i;
+   for (i=0;i<nb_pitch;i++)
+   {
+      /* Compute correlation*/
+      corr[nb_pitch-1-i]=inner_prod(_x, _y+i, len);
+   }
+
+}
+#endif
+#endif
+
+#ifndef OVERRIDE_COMPUTE_PITCH_ERROR
+static inline spx_word32_t compute_pitch_error(spx_word16_t *C, spx_word16_t *g, spx_word16_t pitch_control)
+{
+   spx_word32_t sum = 0;
+   sum = ADD32(sum,MULT16_16(MULT16_16_16(g[0],pitch_control),C[0]));
+   sum = ADD32(sum,MULT16_16(MULT16_16_16(g[1],pitch_control),C[1]));
+   sum = ADD32(sum,MULT16_16(MULT16_16_16(g[2],pitch_control),C[2]));
+   sum = SUB32(sum,MULT16_16(MULT16_16_16(g[0],g[1]),C[3]));
+   sum = SUB32(sum,MULT16_16(MULT16_16_16(g[2],g[1]),C[4]));
+   sum = SUB32(sum,MULT16_16(MULT16_16_16(g[2],g[0]),C[5]));
+   sum = SUB32(sum,MULT16_16(MULT16_16_16(g[0],g[0]),C[6]));
+   sum = SUB32(sum,MULT16_16(MULT16_16_16(g[1],g[1]),C[7]));
+   sum = SUB32(sum,MULT16_16(MULT16_16_16(g[2],g[2]),C[8]));
+   return sum;
+}
+#endif
+
+#ifndef OVERRIDE_OPEN_LOOP_NBEST_PITCH
+void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *pitch, spx_word16_t *gain, int N, char *stack)
+{
+   int i,j,k;
+   VARDECL(spx_word32_t *best_score);
+   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);
+   for (i=0;i<N;i++)
+   {
+        best_score[i]=-1;
+        best_ener[i]=0;
+        pitch[i]=start;
+   }
+   
+#ifdef FIXED_POINT
+   for (i=-end;i<len;i++)
+   {
+      if (ABS16(sw[i])>16383)
+      {
+         scaledown=1;
+         break;
+      }
+   }
+   /* If the weighted input is close to saturation, then we scale it down */
+   if (scaledown)
+   {
+      for (i=-end;i<len;i++)
+      {
+         sw[i]=SHR16(sw[i],1);
+      }
+   }      
+#endif
+   energy[0]=inner_prod(sw-start, sw-start, len);
+   e0=inner_prod(sw, sw, len);
+   for (i=start;i<end;i++)
+   {
+      /* Update energy for next pitch*/
+      energy[i-start+1] = SUB32(ADD32(energy[i-start],SHR32(MULT16_16(sw[-i-1],sw[-i-1]),6)), SHR32(MULT16_16(sw[-i+len-1],sw[-i+len-1]),6));
+      if (energy[i-start+1] < 0)
+         energy[i-start+1] = 0;
+   }
+   
+#ifdef FIXED_POINT
+   eshift = normalize16(energy, ener16, 32766, end-start+1);
+#endif
+   
+   /* In fixed-point, this actually overrites the energy array (aliased to corr) */
+   pitch_xcorr(sw, sw-end, corr, len, end-start+1, stack);
+   
+#ifdef FIXED_POINT
+   /* Normalize to 180 so we can square it and it still fits in 16 bits */
+   cshift = normalize16(corr, corr16, 180, end-start+1);
+   /* If we scaled weighted input down, we need to scale it up again (OK, so we've just lost the LSB, who cares?) */
+   if (scaledown)
+   {
+      for (i=-end;i<len;i++)
+      {
+         sw[i]=SHL16(sw[i],1);
+      }
+   }      
+#endif
+
+   /* Search for the best pitch prediction gain */
+   for (i=start;i<=end;i++)
+   {
+      spx_word16_t tmp = MULT16_16_16(corr16[i-start],corr16[i-start]);
+      /* Instead of dividing the tmp by the energy, we multiply on the other side */
+      if (MULT16_16(tmp,best_ener[N-1])>MULT16_16(best_score[N-1],ADD16(1,ener16[i-start])))
+      {
+         /* We can safely put it last and then check */
+         best_score[N-1]=tmp;
+         best_ener[N-1]=ener16[i-start]+1;
+         pitch[N-1]=i;
+         /* Check if it comes in front of others */
+         for (j=0;j<N-1;j++)
+         {
+            if (MULT16_16(tmp,best_ener[j])>MULT16_16(best_score[j],ADD16(1,ener16[i-start])))
+            {
+               for (k=N-1;k>j;k--)
+               {
+                  best_score[k]=best_score[k-1];
+                  best_ener[k]=best_ener[k-1];
+                  pitch[k]=pitch[k-1];
+               }
+               best_score[j]=tmp;
+               best_ener[j]=ener16[i-start]+1;
+               pitch[j]=i;
+               break;
+            }
+         }
+      }
+   }
+   
+   /* Compute open-loop gain if necessary */
+   if (gain)
+   {
+      for (j=0;j<N;j++)
+      {
+         spx_word16_t g;
+         i=pitch[j];
+         g = DIV32(SHL32(EXTEND32(corr16[i-start]),cshift), 10+SHR32(MULT16_16(spx_sqrt(e0),spx_sqrt(SHL32(EXTEND32(ener16[i-start]),eshift))),6));
+         /* FIXME: g = max(g,corr/energy) */
+         if (g<0)
+            g = 0;
+         gain[j]=g;
+      }
+   }
+
+
+}
+#endif
+
+#ifndef OVERRIDE_PITCH_GAIN_SEARCH_3TAP_VQ
+static int pitch_gain_search_3tap_vq(
+  const signed char *gain_cdbk,
+  int                gain_cdbk_size,
+  spx_word16_t      *C16,
+  spx_word16_t       max_gain
+)
+{
+  const signed char *ptr=gain_cdbk;
+  int                best_cdbk=0;
+  spx_word32_t       best_sum=-VERY_LARGE32;
+  spx_word32_t       sum=0;
+  spx_word16_t       g[3];
+  spx_word16_t       pitch_control=64;
+  spx_word16_t       gain_sum;
+  int                i;
+
+  for (i=0;i<gain_cdbk_size;i++) {
+         
+    ptr = gain_cdbk+4*i;
+    g[0]=ADD16((spx_word16_t)ptr[0],32);
+    g[1]=ADD16((spx_word16_t)ptr[1],32);
+    g[2]=ADD16((spx_word16_t)ptr[2],32);
+    gain_sum = (spx_word16_t)ptr[3];
+         
+    sum = compute_pitch_error(C16, g, pitch_control);
+         
+    if (sum>best_sum && gain_sum<=max_gain) {
+      best_sum=sum;
+      best_cdbk=i;
+    }
+  }
+
+  return best_cdbk;
+}
+#endif
+
+/** Finds the best quantized 3-tap pitch predictor by analysis by synthesis */
+static spx_word32_t pitch_gain_search_3tap(
+const spx_word16_t target[],       /* Target vector */
+const spx_coef_t ak[],          /* LPCs for this subframe */
+const spx_coef_t awk1[],        /* Weighted LPCs #1 for this subframe */
+const spx_coef_t awk2[],        /* Weighted LPCs #2 for this subframe */
+spx_sig_t exc[],                /* Excitation */
+const signed char *gain_cdbk,
+int gain_cdbk_size,
+int   pitch,                    /* Pitch value */
+int   p,                        /* Number of LPC coeffs */
+int   nsf,                      /* Number of samples in subframe */
+SpeexBits *bits,
+char *stack,
+const spx_word16_t *exc2,
+const spx_word16_t *r,
+spx_word16_t *new_target,
+int  *cdbk_index,
+int plc_tuning,
+spx_word32_t cumul_gain,
+int scaledown
+)
+{
+   int i,j;
+   VARDECL(spx_word16_t *tmp1);
+   VARDECL(spx_word16_t *e);
+   spx_word16_t *x[3];
+   spx_word32_t corr[3];
+   spx_word32_t A[3][3];
+   spx_word16_t gain[3];
+   spx_word32_t err;
+   spx_word16_t max_gain=128;
+   int          best_cdbk=0;
+
+   ALLOC(tmp1, 3*nsf, spx_word16_t);
+   ALLOC(e, nsf, spx_word16_t);
+
+   if (cumul_gain > 262144)
+      max_gain = 31;
+   
+   x[0]=tmp1;
+   x[1]=tmp1+nsf;
+   x[2]=tmp1+2*nsf;
+   
+   for (j=0;j<nsf;j++)
+      new_target[j] = target[j];
+
+   {
+      VARDECL(spx_mem_t *mm);
+      int pp=pitch-1;
+      ALLOC(mm, p, spx_mem_t);
+      for (j=0;j<nsf;j++)
+      {
+         if (j-pp<0)
+            e[j]=exc2[j-pp];
+         else if (j-pp-pitch<0)
+            e[j]=exc2[j-pp-pitch];
+         else
+            e[j]=0;
+      }
+#ifdef FIXED_POINT
+      /* Scale target and excitation down if needed (avoiding overflow) */
+      if (scaledown)
+      {
+         for (j=0;j<nsf;j++)
+            e[j] = SHR16(e[j],1);
+         for (j=0;j<nsf;j++)
+            new_target[j] = SHR16(new_target[j],1);
+      }
+#endif
+      for (j=0;j<p;j++)
+         mm[j] = 0;
+      iir_mem16(e, ak, e, nsf, p, mm, stack);
+      for (j=0;j<p;j++)
+         mm[j] = 0;
+      filter_mem16(e, awk1, awk2, e, nsf, p, mm, stack);
+      for (j=0;j<nsf;j++)
+         x[2][j] = e[j];
+   }
+   for (i=1;i>=0;i--)
+   {
+      spx_word16_t e0=exc2[-pitch-1+i];
+#ifdef FIXED_POINT
+      /* Scale excitation down if needed (avoiding overflow) */
+      if (scaledown)
+         e0 = SHR16(e0,1);
+#endif
+      x[i][0]=MULT16_16_Q14(r[0], e0);
+      for (j=0;j<nsf-1;j++)
+         x[i][j+1]=ADD32(x[i+1][j],MULT16_16_P14(r[j+1], e0));
+   }
+
+   for (i=0;i<3;i++)
+      corr[i]=inner_prod(x[i],new_target,nsf);
+   for (i=0;i<3;i++)
+      for (j=0;j<=i;j++)
+         A[i][j]=A[j][i]=inner_prod(x[i],x[j],nsf);
+
+   {
+      spx_word32_t C[9];
+#ifdef FIXED_POINT
+      spx_word16_t C16[9];
+#else
+      spx_word16_t *C16=C;
+#endif      
+      C[0]=corr[2];
+      C[1]=corr[1];
+      C[2]=corr[0];
+      C[3]=A[1][2];
+      C[4]=A[0][1];
+      C[5]=A[0][2];      
+      C[6]=A[2][2];
+      C[7]=A[1][1];
+      C[8]=A[0][0];
+      
+      /*plc_tuning *= 2;*/
+      if (plc_tuning<2)
+         plc_tuning=2;
+      if (plc_tuning>30)
+         plc_tuning=30;
+#ifdef FIXED_POINT
+      C[0] = SHL32(C[0],1);
+      C[1] = SHL32(C[1],1);
+      C[2] = SHL32(C[2],1);
+      C[3] = SHL32(C[3],1);
+      C[4] = SHL32(C[4],1);
+      C[5] = SHL32(C[5],1);
+      C[6] = MAC16_32_Q15(C[6],MULT16_16_16(plc_tuning,655),C[6]);
+      C[7] = MAC16_32_Q15(C[7],MULT16_16_16(plc_tuning,655),C[7]);
+      C[8] = MAC16_32_Q15(C[8],MULT16_16_16(plc_tuning,655),C[8]);
+      normalize16(C, C16, 32767, 9);
+#else
+      C[6]*=.5*(1+.02*plc_tuning);
+      C[7]*=.5*(1+.02*plc_tuning);
+      C[8]*=.5*(1+.02*plc_tuning);
+#endif
+
+      best_cdbk = pitch_gain_search_3tap_vq(gain_cdbk, gain_cdbk_size, C16, max_gain);
+
+#ifdef FIXED_POINT
+      gain[0] = ADD16(32,(spx_word16_t)gain_cdbk[best_cdbk*4]);
+      gain[1] = ADD16(32,(spx_word16_t)gain_cdbk[best_cdbk*4+1]);
+      gain[2] = ADD16(32,(spx_word16_t)gain_cdbk[best_cdbk*4+2]);
+      /*printf ("%d %d %d %d\n",gain[0],gain[1],gain[2], best_cdbk);*/
+#else
+      gain[0] = 0.015625*gain_cdbk[best_cdbk*4]  + .5;
+      gain[1] = 0.015625*gain_cdbk[best_cdbk*4+1]+ .5;
+      gain[2] = 0.015625*gain_cdbk[best_cdbk*4+2]+ .5;
+#endif
+      *cdbk_index=best_cdbk;
+   }
+
+   for (i=0;i<nsf;i++)
+      exc[i]=0;
+   for (i=0;i<3;i++)
+   {
+      int j;
+      int tmp1, tmp3;
+      int pp=pitch+1-i;
+      tmp1=nsf;
+      if (tmp1>pp)
+         tmp1=pp;
+      for (j=0;j<tmp1;j++)
+         exc[j]=MAC16_16(exc[j],SHL16(gain[2-i],7),exc2[j-pp]);
+      tmp3=nsf;
+      if (tmp3>pp+pitch)
+         tmp3=pp+pitch;
+      for (j=tmp1;j<tmp3;j++)
+         exc[j]=MAC16_16(exc[j],SHL16(gain[2-i],7),exc2[j-pp-pitch]);
+   }
+   for (i=0;i<nsf;i++)
+   {
+      spx_word32_t tmp = ADD32(ADD32(MULT16_16(gain[0],x[2][i]),MULT16_16(gain[1],x[1][i])),
+                            MULT16_16(gain[2],x[0][i]));
+      new_target[i] = SUB16(new_target[i], EXTRACT16(PSHR32(tmp,6)));
+   }
+   err = inner_prod(new_target, new_target, nsf);
+
+   return err;
+}
+
+/** Finds the best quantized 3-tap pitch predictor by analysis by synthesis */
+int pitch_search_3tap(
+spx_word16_t target[],                 /* Target vector */
+spx_word16_t *sw,
+spx_coef_t ak[],                     /* LPCs for this subframe */
+spx_coef_t awk1[],                   /* Weighted LPCs #1 for this subframe */
+spx_coef_t awk2[],                   /* Weighted LPCs #2 for this subframe */
+spx_sig_t exc[],                    /* Excitation */
+const void *par,
+int   start,                    /* Smallest pitch value allowed */
+int   end,                      /* Largest pitch value allowed */
+spx_word16_t pitch_coef,               /* Voicing (pitch) coefficient */
+int   p,                        /* Number of LPC coeffs */
+int   nsf,                      /* Number of samples in subframe */
+SpeexBits *bits,
+char *stack,
+spx_word16_t *exc2,
+spx_word16_t *r,
+int complexity,
+int cdbk_offset,
+int plc_tuning,
+spx_word32_t *cumul_gain
+)
+{
+   int i,j;
+   int cdbk_index, pitch=0, best_gain_index=0;
+   VARDECL(spx_sig_t *best_exc);
+   VARDECL(spx_word16_t *new_target);
+   VARDECL(spx_word16_t *best_target);
+   int best_pitch=0;
+   spx_word32_t err, best_err=-1;
+   int N;
+   const ltp_params *params;
+   const signed char *gain_cdbk;
+   int   gain_cdbk_size;
+   int scaledown=0;
+         
+   VARDECL(int *nbest);
+   
+   params = (const ltp_params*) par;
+   gain_cdbk_size = 1<<params->gain_bits;
+   gain_cdbk = params->gain_cdbk + 4*gain_cdbk_size*cdbk_offset;
+   
+   N=complexity;
+   if (N>10)
+      N=10;
+   if (N<1)
+      N=1;
+
+   ALLOC(nbest, N, int);
+   params = (const ltp_params*) par;
+
+   if (end<start)
+   {
+      speex_bits_pack(bits, 0, params->pitch_bits);
+      speex_bits_pack(bits, 0, params->gain_bits);
+      for (i=0;i<nsf;i++)
+         exc[i]=0;
+      return start;
+   }
+   
+#ifdef FIXED_POINT
+   /* Check if we need to scale everything down in the pitch search to avoid overflows */
+   for (i=0;i<nsf;i++)
+   {
+      if (ABS16(target[i])>16383)
+      {
+         scaledown=1;
+         break;
+      }
+   }
+   for (i=-end;i<nsf;i++)
+   {
+      if (ABS16(exc2[i])>16383)
+      {
+         scaledown=1;
+         break;
+      }
+   }
+#endif
+   if (N>end-start+1)
+      N=end-start+1;
+   if (end != start)
+      open_loop_nbest_pitch(sw, start, end, nsf, nbest, NULL, N, stack);
+   else
+      nbest[0] = start;
+   
+   ALLOC(best_exc, nsf, spx_sig_t);
+   ALLOC(new_target, nsf, spx_word16_t);
+   ALLOC(best_target, nsf, spx_word16_t);
+   
+   for (i=0;i<N;i++)
+   {
+      pitch=nbest[i];
+      for (j=0;j<nsf;j++)
+         exc[j]=0;
+      err=pitch_gain_search_3tap(target, ak, awk1, awk2, exc, gain_cdbk, gain_cdbk_size, pitch, p, nsf,
+                                 bits, stack, exc2, r, new_target, &cdbk_index, plc_tuning, *cumul_gain, scaledown);
+      if (err<best_err || best_err<0)
+      {
+         for (j=0;j<nsf;j++)
+            best_exc[j]=exc[j];
+         for (j=0;j<nsf;j++)
+            best_target[j]=new_target[j];
+         best_err=err;
+         best_pitch=pitch;
+         best_gain_index=cdbk_index;
+      }
+   }
+   /*printf ("pitch: %d %d\n", best_pitch, best_gain_index);*/
+   speex_bits_pack(bits, best_pitch-start, params->pitch_bits);
+   speex_bits_pack(bits, best_gain_index, params->gain_bits);
+#ifdef FIXED_POINT
+   *cumul_gain = MULT16_32_Q13(SHL16(params->gain_cdbk[4*best_gain_index+3],8), MAX32(1024,*cumul_gain));
+#else
+   *cumul_gain = 0.03125*MAX32(1024,*cumul_gain)*params->gain_cdbk[4*best_gain_index+3];
+#endif
+   /*printf ("%f\n", cumul_gain);*/
+   /*printf ("encode pitch: %d %d\n", best_pitch, best_gain_index);*/
+   for (i=0;i<nsf;i++)
+      exc[i]=best_exc[i];
+   for (i=0;i<nsf;i++)
+      target[i]=best_target[i];
+#ifdef FIXED_POINT
+   /* Scale target back up if needed */
+   if (scaledown)
+   {
+      for (i=0;i<nsf;i++)
+         target[i]=SHL16(target[i],1);
+   }
+#endif
+   return pitch;
+}
+
+void pitch_unquant_3tap(
+spx_word16_t exc[],             /* Input excitation */
+spx_word32_t exc_out[],         /* Output excitation */
+int   start,                    /* Smallest pitch value allowed */
+int   end,                      /* Largest pitch value allowed */
+spx_word16_t pitch_coef,        /* Voicing (pitch) coefficient */
+const void *par,
+int   nsf,                      /* Number of samples in subframe */
+int *pitch_val,
+spx_word16_t *gain_val,
+SpeexBits *bits,
+char *stack,
+int count_lost,
+int subframe_offset,
+spx_word16_t last_pitch_gain,
+int cdbk_offset
+)
+{
+   int i;
+   int pitch;
+   int gain_index;
+   spx_word16_t gain[3];
+   const signed char *gain_cdbk;
+   int gain_cdbk_size;
+   const ltp_params *params;
+
+   params = (const ltp_params*) par;
+   gain_cdbk_size = 1<<params->gain_bits;
+   gain_cdbk = params->gain_cdbk + 4*gain_cdbk_size*cdbk_offset;
+
+   pitch = speex_bits_unpack_unsigned(bits, params->pitch_bits);
+   pitch += start;
+   gain_index = speex_bits_unpack_unsigned(bits, params->gain_bits);
+   /*printf ("decode pitch: %d %d\n", pitch, gain_index);*/
+#ifdef FIXED_POINT
+   gain[0] = ADD16(32,(spx_word16_t)gain_cdbk[gain_index*4]);
+   gain[1] = ADD16(32,(spx_word16_t)gain_cdbk[gain_index*4+1]);
+   gain[2] = ADD16(32,(spx_word16_t)gain_cdbk[gain_index*4+2]);
+#else
+   gain[0] = 0.015625*gain_cdbk[gain_index*4]+.5;
+   gain[1] = 0.015625*gain_cdbk[gain_index*4+1]+.5;
+   gain[2] = 0.015625*gain_cdbk[gain_index*4+2]+.5;
+#endif
+
+   if (count_lost && pitch > subframe_offset)
+   {
+      spx_word16_t gain_sum;
+      if (1) {
+#ifdef FIXED_POINT
+         spx_word16_t tmp = count_lost < 4 ? last_pitch_gain : SHR16(last_pitch_gain,1);
+         if (tmp>62)
+            tmp=62;
+#else
+         spx_word16_t tmp = count_lost < 4 ? last_pitch_gain : 0.5 * last_pitch_gain;
+         if (tmp>.95)
+            tmp=.95;
+#endif
+         gain_sum = gain_3tap_to_1tap(gain);
+
+         if (gain_sum > tmp)
+         {
+            spx_word16_t fact = DIV32_16(SHL32(EXTEND32(tmp),14),gain_sum);
+            for (i=0;i<3;i++)
+               gain[i]=MULT16_16_Q14(fact,gain[i]);
+         }
+
+      }
+
+   }
+
+   *pitch_val = pitch;
+   gain_val[0]=gain[0];
+   gain_val[1]=gain[1];
+   gain_val[2]=gain[2];
+   gain[0] = SHL16(gain[0],7);
+   gain[1] = SHL16(gain[1],7);
+   gain[2] = SHL16(gain[2],7);
+   for (i=0;i<nsf;i++)
+      exc_out[i]=0;
+   for (i=0;i<3;i++)
+   {
+      int j;
+      int tmp1, tmp3;
+      int pp=pitch+1-i;
+      tmp1=nsf;
+      if (tmp1>pp)
+         tmp1=pp;
+      for (j=0;j<tmp1;j++)
+         exc_out[j]=MAC16_16(exc_out[j],gain[2-i],exc[j-pp]);
+      tmp3=nsf;
+      if (tmp3>pp+pitch)
+         tmp3=pp+pitch;
+      for (j=tmp1;j<tmp3;j++)
+         exc_out[j]=MAC16_16(exc_out[j],gain[2-i],exc[j-pp-pitch]);
+   }
+   /*for (i=0;i<nsf;i++)
+   exc[i]=PSHR32(exc32[i],13);*/
+}
+
+
+/** Forced pitch delay and gain */
+int forced_pitch_quant(
+spx_word16_t target[],                 /* Target vector */
+spx_word16_t *sw,
+spx_coef_t ak[],                     /* LPCs for this subframe */
+spx_coef_t awk1[],                   /* Weighted LPCs #1 for this subframe */
+spx_coef_t awk2[],                   /* Weighted LPCs #2 for this subframe */
+spx_sig_t exc[],                    /* Excitation */
+const void *par,
+int   start,                    /* Smallest pitch value allowed */
+int   end,                      /* Largest pitch value allowed */
+spx_word16_t pitch_coef,               /* Voicing (pitch) coefficient */
+int   p,                        /* Number of LPC coeffs */
+int   nsf,                      /* Number of samples in subframe */
+SpeexBits *bits,
+char *stack,
+spx_word16_t *exc2,
+spx_word16_t *r,
+int complexity,
+int cdbk_offset,
+int plc_tuning,
+spx_word32_t *cumul_gain
+)
+{
+   int i;
+   VARDECL(spx_word16_t *res);
+   ALLOC(res, nsf, spx_word16_t);
+#ifdef FIXED_POINT
+   if (pitch_coef>63)
+      pitch_coef=63;
+#else
+   if (pitch_coef>.99)
+      pitch_coef=.99;
+#endif
+   for (i=0;i<nsf&&i<start;i++)
+   {
+      exc[i]=MULT16_16(SHL16(pitch_coef, 7),exc2[i-start]);
+   }
+   for (;i<nsf;i++)
+   {
+      exc[i]=MULT16_32_Q15(SHL16(pitch_coef, 9),exc[i-start]);
+   }
+   for (i=0;i<nsf;i++)
+      res[i] = EXTRACT16(PSHR32(exc[i], SIG_SHIFT-1));
+   syn_percep_zero16(res, ak, awk1, awk2, res, nsf, p, stack);
+   for (i=0;i<nsf;i++)
+      target[i]=EXTRACT16(SATURATE(SUB32(EXTEND32(target[i]),EXTEND32(res[i])),32700));
+   return start;
+}
+
+/** Unquantize forced pitch delay and gain */
+void forced_pitch_unquant(
+spx_word16_t exc[],             /* Input excitation */
+spx_word32_t exc_out[],         /* Output excitation */
+int   start,                    /* Smallest pitch value allowed */
+int   end,                      /* Largest pitch value allowed */
+spx_word16_t pitch_coef,        /* Voicing (pitch) coefficient */
+const void *par,
+int   nsf,                      /* Number of samples in subframe */
+int *pitch_val,
+spx_word16_t *gain_val,
+SpeexBits *bits,
+char *stack,
+int count_lost,
+int subframe_offset,
+spx_word16_t last_pitch_gain,
+int cdbk_offset
+)
+{
+   int i;
+#ifdef FIXED_POINT
+   if (pitch_coef>63)
+      pitch_coef=63;
+#else
+   if (pitch_coef>.99)
+      pitch_coef=.99;
+#endif
+   for (i=0;i<nsf;i++)
+   {
+      exc_out[i]=MULT16_16(exc[i-start],SHL16(pitch_coef,7));
+      exc[i] = EXTRACT16(PSHR32(exc_out[i],13));
+   }
+   *pitch_val = start;
+   gain_val[0]=gain_val[2]=0;
+   gain_val[1] = pitch_coef;
+}
diff --git a/3rdparty/speex/libspeex/ltp.h b/3rdparty/speex/libspeex/ltp.h
new file mode 100644
index 0000000..bc050c6
--- /dev/null
+++ b/3rdparty/speex/libspeex/ltp.h
@@ -0,0 +1,141 @@
+/* Copyright (C) 2002 Jean-Marc Valin */
+/**
+   @file ltp.h
+   @brief Long-Term Prediction functions
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <speex/speex_bits.h>
+#include "misc.h"
+
+/** LTP parameters. */
+typedef struct {
+   const signed char *gain_cdbk;
+   int     gain_bits;
+   int     pitch_bits;
+} ltp_params;
+
+#ifdef FIXED_POINT
+#define gain_3tap_to_1tap(g) (ABS(g[1]) + (g[0]>0 ? g[0] : -SHR16(g[0],1)) + (g[2]>0 ? g[2] : -SHR16(g[2],1)))
+#else
+#define gain_3tap_to_1tap(g) (ABS(g[1]) + (g[0]>0 ? g[0] : -.5*g[0]) + (g[2]>0 ? g[2] : -.5*g[2]))
+#endif
+
+spx_word32_t inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len);
+void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack);
+
+void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *pitch, spx_word16_t *gain, int N, char *stack);
+
+
+/** Finds the best quantized 3-tap pitch predictor by analysis by synthesis */
+int pitch_search_3tap(
+spx_word16_t target[],                 /* Target vector */
+spx_word16_t *sw,
+spx_coef_t ak[],                     /* LPCs for this subframe */
+spx_coef_t awk1[],                   /* Weighted LPCs #1 for this subframe */
+spx_coef_t awk2[],                   /* Weighted LPCs #2 for this subframe */
+spx_sig_t exc[],                    /* Overlapping codebook */
+const void *par,
+int   start,                    /* Smallest pitch value allowed */
+int   end,                      /* Largest pitch value allowed */
+spx_word16_t pitch_coef,               /* Voicing (pitch) coefficient */
+int   p,                        /* Number of LPC coeffs */
+int   nsf,                      /* Number of samples in subframe */
+SpeexBits *bits,
+char *stack,
+spx_word16_t *exc2,
+spx_word16_t *r,
+int   complexity,
+int   cdbk_offset,
+int plc_tuning,
+spx_word32_t *cumul_gain
+);
+
+/*Unquantize adaptive codebook and update pitch contribution*/
+void pitch_unquant_3tap(
+spx_word16_t exc[],             /* Input excitation */
+spx_word32_t exc_out[],         /* Output excitation */
+int   start,                    /* Smallest pitch value allowed */
+int   end,                      /* Largest pitch value allowed */
+spx_word16_t pitch_coef,        /* Voicing (pitch) coefficient */
+const void *par,
+int   nsf,                      /* Number of samples in subframe */
+int *pitch_val,
+spx_word16_t *gain_val,
+SpeexBits *bits,
+char *stack,
+int lost,
+int subframe_offset,
+spx_word16_t last_pitch_gain,
+int cdbk_offset
+);
+
+/** Forced pitch delay and gain */
+int forced_pitch_quant(
+spx_word16_t target[],                 /* Target vector */
+spx_word16_t *sw,
+spx_coef_t ak[],                     /* LPCs for this subframe */
+spx_coef_t awk1[],                   /* Weighted LPCs #1 for this subframe */
+spx_coef_t awk2[],                   /* Weighted LPCs #2 for this subframe */
+spx_sig_t exc[],                    /* Excitation */
+const void *par,
+int   start,                    /* Smallest pitch value allowed */
+int   end,                      /* Largest pitch value allowed */
+spx_word16_t pitch_coef,               /* Voicing (pitch) coefficient */
+int   p,                        /* Number of LPC coeffs */
+int   nsf,                      /* Number of samples in subframe */
+SpeexBits *bits,
+char *stack,
+spx_word16_t *exc2,
+spx_word16_t *r,
+int complexity,
+int cdbk_offset,
+int plc_tuning,
+spx_word32_t *cumul_gain
+);
+
+/** Unquantize forced pitch delay and gain */
+void forced_pitch_unquant(
+spx_word16_t exc[],             /* Input excitation */
+spx_word32_t exc_out[],         /* Output excitation */
+int   start,                    /* Smallest pitch value allowed */
+int   end,                      /* Largest pitch value allowed */
+spx_word16_t pitch_coef,        /* Voicing (pitch) coefficient */
+const void *par,
+int   nsf,                      /* Number of samples in subframe */
+int *pitch_val,
+spx_word16_t *gain_val,
+SpeexBits *bits,
+char *stack,
+int lost,
+int subframe_offset,
+spx_word16_t last_pitch_gain,
+int cdbk_offset
+);
diff --git a/3rdparty/speex/libspeex/ltp_arm4.h b/3rdparty/speex/libspeex/ltp_arm4.h
new file mode 100644
index 0000000..7479e8b
--- /dev/null
+++ b/3rdparty/speex/libspeex/ltp_arm4.h
@@ -0,0 +1,188 @@
+/* Copyright (C) 2004 Jean-Marc Valin */
+/**
+   @file ltp_arm4.h
+   @brief Long-Term Prediction functions (ARM4 version)
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define OVERRIDE_INNER_PROD
+spx_word32_t inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len)
+{
+   spx_word32_t sum1=0,sum2=0;
+   spx_word16_t *deadx, *deady;
+   int deadlen, dead1, dead2, dead3, dead4, dead5, dead6;
+   __asm__ __volatile__ (
+         "\tldrsh %5, [%0], #2 \n"
+         "\tldrsh %6, [%1], #2 \n"
+         ".inner_prod_loop%=:\n"
+         "\tsub %7, %7, %7\n"
+         "\tsub %10, %10, %10\n"
+
+         "\tldrsh %8, [%0], #2 \n"
+         "\tldrsh %9, [%1], #2 \n"
+         "\tmla %7, %5, %6, %7\n"
+         "\tldrsh %5, [%0], #2 \n"
+         "\tldrsh %6, [%1], #2 \n"
+         "\tmla %10, %8, %9, %10\n"
+         "\tldrsh %8, [%0], #2 \n"
+         "\tldrsh %9, [%1], #2 \n"
+         "\tmla %7, %5, %6, %7\n"
+         "\tldrsh %5, [%0], #2 \n"
+         "\tldrsh %6, [%1], #2 \n"
+         "\tmla %10, %8, %9, %10\n"
+
+         "\tldrsh %8, [%0], #2 \n"
+         "\tldrsh %9, [%1], #2 \n"
+         "\tmla %7, %5, %6, %7\n"
+         "\tldrsh %5, [%0], #2 \n"
+         "\tldrsh %6, [%1], #2 \n"
+         "\tmla %10, %8, %9, %10\n"
+         "\tldrsh %8, [%0], #2 \n"
+         "\tldrsh %9, [%1], #2 \n"
+         "\tmla %7, %5, %6, %7\n"
+         "\tldrsh %5, [%0], #2 \n"
+         "\tldrsh %6, [%1], #2 \n"
+         "\tmla %10, %8, %9, %10\n"
+
+         "\tsubs %4, %4, #1\n"
+         "\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)
+   : "cc"
+                        );
+   return (sum1+sum2)>>1;
+}
+
+#define OVERRIDE_PITCH_XCORR
+void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack)
+{
+   int i,j;
+   for (i=0;i<nb_pitch;i+=4)
+   {
+      /* Compute correlation*/
+      //corr[nb_pitch-1-i]=inner_prod(x, _y+i, len);
+      spx_word32_t sum1=0;
+      spx_word32_t sum2=0;
+      spx_word32_t sum3=0;
+      spx_word32_t sum4=0;
+      const spx_word16_t *y = _y+i;
+      const spx_word16_t *x = _x;
+      spx_word32_t y0, y1, y2, y3;
+      y0=*y++;
+      y1=*y++;
+      y2=*y++;
+      y3=*y++;
+      for (j=0;j<len;j+=4)
+      {
+         spx_word32_t part1, part2, part3, part4, x0;
+         spx_word32_t dead1;
+         __asm__ __volatile__ (
+#ifdef SHORTCUTS
+               "\tldrsh %10, [%8], #4 \n"
+               "\tmul %4, %10, %0 \n"
+               "\tldrsh %15, [%8], #4 \n"
+               "\tmul %5, %10, %1 \n"
+               "\tldrsh %0, [%9], #2 \n"
+               "\tmul %6, %10, %2 \n"
+               "\tldrsh %1, [%9], #2 \n"
+               "\tmul %7, %10, %3 \n"
+               
+               
+               "\tmla %4, %15, %2, %4 \n"
+               "\tldrsh %2, [%9], #2 \n"
+               "\tmla %5, %15, %3, %5 \n"
+               "\tldrsh %3, [%9], #2 \n"
+               "\tmla %6, %15, %0, %6 \n"
+               "\tmla %7, %15, %1, %7 \n"
+
+#else
+               "\tldrsh %10, [%8], #2 \n"
+               "\tmul %4, %10, %0 \n"
+               "\tmul %5, %10, %1 \n"
+               "\tmul %6, %10, %2 \n"
+               "\tmul %7, %10, %3 \n"
+
+               "\tldrsh %10, [%8], #2 \n"
+               "\tldrsh %0, [%9], #2 \n"
+               "\tmla %4, %10, %1, %4 \n"
+               "\tmla %5, %10, %2, %5 \n"
+               "\tmla %6, %10, %3, %6 \n"
+               "\tmla %7, %10, %0, %7 \n"
+
+               "\tldrsh %10, [%8], #2 \n"
+               "\tldrsh %1, [%9], #2 \n"
+               "\tmla %4, %10, %2, %4 \n"
+               "\tmla %5, %10, %3, %5 \n"
+               "\tmla %6, %10, %0, %6 \n"
+               "\tmla %7, %10, %1, %7 \n"
+
+               "\tldrsh %10, [%8], #2 \n"
+               "\tldrsh %2, [%9], #2 \n"
+               "\tmla %4, %10, %3, %4 \n"
+               "\tmla %5, %10, %0, %5 \n"
+               "\tmla %6, %10, %1, %6 \n"
+               "\tmla %7, %10, %2, %7 \n"
+
+               "\tldrsh %3, [%9], #2 \n"
+#endif
+
+               "\tldr %10, %11 \n"
+               "\tldr %15, %12 \n"
+               "\tadd %4, %10, %4, asr #6 \n"
+               "\tstr %4, %11 \n"
+               "\tldr %10, %13 \n"
+               "\tadd %5, %15, %5, asr #6 \n"
+               "\tstr %5, %12 \n"
+               "\tldr %15, %14 \n"
+               "\tadd %6, %10, %6, asr #6 \n"
+               "\tadd %7, %15, %7, asr #6 \n"
+               "\tstr %6, %13 \n"
+               "\tstr %7, %14 \n"
+
+            : "=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)
+            : "cc", "memory"
+                              );
+      }
+      corr[nb_pitch-1-i]=sum1;
+      corr[nb_pitch-2-i]=sum2;
+      corr[nb_pitch-3-i]=sum3;
+      corr[nb_pitch-4-i]=sum4;
+   }
+
+}
diff --git a/3rdparty/speex/libspeex/ltp_bfin.h b/3rdparty/speex/libspeex/ltp_bfin.h
new file mode 100644
index 0000000..c466902
--- /dev/null
+++ b/3rdparty/speex/libspeex/ltp_bfin.h
@@ -0,0 +1,419 @@
+/* Copyright (C) 2005 Analog Devices */
+/**
+   @file ltp_bfin.h
+   @author Jean-Marc Valin
+   @brief Long-Term Prediction functions (Blackfin version)
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define OVERRIDE_INNER_PROD
+spx_word32_t inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len)
+{
+   spx_word32_t sum=0;
+   __asm__ __volatile__ (
+      "P0 = %3;\n\t"
+      "P1 = %1;\n\t"
+      "P2 = %2;\n\t"
+      "I0 = P1;\n\t"
+      "I1 = P2;\n\t"
+      "L0 = 0;\n\t"
+      "L1 = 0;\n\t"
+      "A0 = 0;\n\t"
+      "R0.L = W[I0++] || R1.L = W[I1++];\n\t"
+      "LOOP inner%= LC0 = P0;\n\t"
+      "LOOP_BEGIN inner%=;\n\t"
+         "A0 += R0.L*R1.L (IS) || R0.L = W[I0++] || R1.L = W[I1++];\n\t"
+      "LOOP_END inner%=;\n\t"
+      "A0 += R0.L*R1.L (IS);\n\t"
+      "A0 = A0 >>> 6;\n\t"
+      "R0 = A0;\n\t"
+      "%0 = R0;\n\t"
+   : "=m" (sum)
+   : "m" (x), "m" (y), "d" (len-1)
+   : "P0", "P1", "P2", "R0", "R1", "A0", "I0", "I1", "L0", "L1", "R3"
+   );
+   return sum;
+}
+
+#define OVERRIDE_PITCH_XCORR
+void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *corr, int len, int nb_pitch, char *stack)
+{
+   corr += nb_pitch - 1;
+   __asm__ __volatile__ (
+      "P2 = %0;\n\t"
+      "I0 = P2;\n\t" /* x in I0 */
+      "B0 = P2;\n\t" /* x in B0 */
+      "R0 = %3;\n\t" /* len in R0 */
+      "P3 = %3;\n\t"
+      "P3 += -2;\n\t" /* len in R0 */
+      "P4 = %4;\n\t" /* nb_pitch in R0 */
+      "R1 = R0 << 1;\n\t" /* number of bytes in x */
+      "L0 = R1;\n\t"
+      "P0 = %1;\n\t"
+
+      "P1 = %2;\n\t"
+      "B1 = P1;\n\t"
+      "L1 = 0;\n\t" /*Disable looping on I1*/
+
+      "r0 = [I0++];\n\t"
+      "LOOP pitch%= LC0 = P4 >> 1;\n\t"
+      "LOOP_BEGIN pitch%=;\n\t"
+         "I1 = P0;\n\t"
+         "A1 = A0 = 0;\n\t"
+         "R1 = [I1++];\n\t"
+         "LOOP inner_prod%= LC1 = P3 >> 1;\n\t"
+         "LOOP_BEGIN inner_prod%=;\n\t"
+            "A1 += R0.L*R1.H, A0 += R0.L*R1.L (IS) || R1.L = W[I1++];\n\t"
+            "A1 += R0.H*R1.L, A0 += R0.H*R1.H (IS) || R1.H = W[I1++] || R0 = [I0++];\n\t"
+         "LOOP_END inner_prod%=;\n\t"
+         "A1 += R0.L*R1.H, A0 += R0.L*R1.L (IS) || R1.L = W[I1++];\n\t"
+         "A1 += R0.H*R1.L, A0 += R0.H*R1.H (IS) || R0 = [I0++];\n\t"
+         "A0 = A0 >>> 6;\n\t"
+         "A1 = A1 >>> 6;\n\t"
+         "R2 = A0, R3 = A1;\n\t"
+         "[P1--] = r2;\n\t"
+         "[P1--] = r3;\n\t"
+         "P0 += 4;\n\t"
+      "LOOP_END pitch%=;\n\t"
+      "L0 = 0;\n\t"
+   : : "m" (_x), "m" (_y), "m" (corr), "m" (len), "m" (nb_pitch)
+   : "A0", "A1", "P0", "P1", "P2", "P3", "P4", "R0", "R1", "R2", "R3", "I0", "I1", "L0", "L1", "B0", "B1", "memory"
+   );
+}
+
+#define OVERRIDE_COMPUTE_PITCH_ERROR
+static inline spx_word32_t compute_pitch_error(spx_word16_t *C, spx_word16_t *g, spx_word16_t pitch_control)
+{
+   spx_word32_t sum;
+   __asm__ __volatile__
+         (
+         "A0 = 0;\n\t"
+         
+         "R0 = W[%1++];\n\t"
+         "R1.L = %2.L*%5.L (IS);\n\t"
+         "A0 += R1.L*R0.L (IS) || R0 = W[%1++];\n\t"
+         
+         "R1.L = %3.L*%5.L (IS);\n\t"
+         "A0 += R1.L*R0.L (IS) || R0 = W[%1++];\n\t"
+         
+         "R1.L = %4.L*%5.L (IS);\n\t"
+         "A0 += R1.L*R0.L (IS) || R0 = W[%1++];\n\t"
+         
+         "R1.L = %2.L*%3.L (IS);\n\t"
+         "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t"
+
+         "R1.L = %4.L*%3.L (IS);\n\t"
+         "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t"
+         
+         "R1.L = %4.L*%2.L (IS);\n\t"
+         "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t"
+         
+         "R1.L = %2.L*%2.L (IS);\n\t"
+         "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t"
+
+         "R1.L = %3.L*%3.L (IS);\n\t"
+         "A0 -= R1.L*R0.L (IS) || R0 = W[%1++];\n\t"
+         
+         "R1.L = %4.L*%4.L (IS);\n\t"
+         "A0 -= R1.L*R0.L (IS);\n\t"
+         
+         "%0 = A0;\n\t"
+   : "=&D" (sum), "=a" (C)
+   : "d" (g[0]), "d" (g[1]), "d" (g[2]), "d" (pitch_control), "1" (C)
+   : "R0", "R1", "R2", "A0"
+         );
+   return sum;
+}
+
+#define OVERRIDE_OPEN_LOOP_NBEST_PITCH
+#ifdef OVERRIDE_OPEN_LOOP_NBEST_PITCH
+void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *pitch, spx_word16_t *gain, int N, char *stack)
+{
+   int i,j,k;
+   VARDECL(spx_word32_t *best_score);
+   VARDECL(spx_word32_t *best_ener);
+   spx_word32_t e0;
+   VARDECL(spx_word32_t *corr);
+   VARDECL(spx_word32_t *energy);
+
+   ALLOC(best_score, N, spx_word32_t);
+   ALLOC(best_ener, N, spx_word32_t);
+   ALLOC(corr, end-start+1, spx_word32_t);
+   ALLOC(energy, end-start+2, spx_word32_t);
+
+   for (i=0;i<N;i++)
+   {
+        best_score[i]=-1;
+        best_ener[i]=0;
+        pitch[i]=start;
+   }
+
+   energy[0]=inner_prod(sw-start, sw-start, len);
+   e0=inner_prod(sw, sw, len);
+
+   /* energy update -------------------------------------*/
+
+      __asm__ __volatile__
+      (
+"        P0 = %0;\n\t"
+"        I1 = %1;\n\t"
+"        L1 = 0;\n\t"
+"        I2 = %2;\n\t"
+"        L2 = 0;\n\t"
+"        R2 = [P0++];\n\t"
+"        R3 = 0;\n\t"
+"        LSETUP (eu1, eu2) LC1 = %3;\n\t"
+"eu1:      R1.L = W [I1--] || R0.L = W [I2--] ;\n\t"
+"          R1 = R1.L * R1.L (IS);\n\t"
+"          R0 = R0.L * R0.L (IS);\n\t"
+"          R1 >>>= 6;\n\t"
+"          R1 = R1 + R2;\n\t"
+"          R0 >>>= 6;\n\t"
+"          R1 = R1 - R0;\n\t"
+"          R2 = MAX(R1,R3);\n\t"
+"eu2:      [P0++] = R2;\n\t"
+       : : "d" (energy), "d" (&sw[-start-1]), "d" (&sw[-start+len-1]),
+           "a" (end-start)  
+       : "P0", "I1", "I2", "R0", "R1", "R2", "R3"
+#if (__GNUC__ == 4)
+         , "LC1"
+#endif
+       );
+
+   pitch_xcorr(sw, sw-end, corr, len, end-start+1, stack);
+
+   /* FIXME: Fixed-point and floating-point code should be merged */
+   {
+      VARDECL(spx_word16_t *corr16);
+      VARDECL(spx_word16_t *ener16);
+      ALLOC(corr16, end-start+1, spx_word16_t);
+      ALLOC(ener16, end-start+1, spx_word16_t);
+      /* Normalize to 180 so we can square it and it still fits in 16 bits */
+      normalize16(corr, corr16, 180, end-start+1);
+      normalize16(energy, ener16, 180, end-start+1);
+
+      if (N == 1) {
+	/* optimised asm to handle N==1 case */
+      __asm__ __volatile__
+      (
+"        I0 = %1;\n\t"                     /* I0: corr16[]    */
+"        L0 = 0;\n\t"
+"        I1 = %2;\n\t"                     /* I1: energy      */
+"        L1 = 0;\n\t"
+"        R2 = -1;\n\t"                     /* R2: best score  */
+"        R3 = 0;\n\t"                      /* R3: best energy */
+"        P0 = %4;\n\t"                     /* P0: best pitch  */
+"        P1 = %4;\n\t"                     /* P1: counter     */
+"        LSETUP (sl1, sl2) LC1 = %3;\n\t"
+"sl1:      R0.L = W [I0++] || R1.L = W [I1++];\n\t"         
+"          R0 = R0.L * R0.L (IS);\n\t"
+"          R1   += 1;\n\t"
+"          R4   = R0.L * R3.L;\n\t"
+"          R5   = R2.L * R1.L;\n\t"
+"          cc   = R5 < R4;\n\t"
+"          if cc R2 = R0;\n\t"
+"          if cc R3 = R1;\n\t"
+"          if cc P0 = P1;\n\t"
+"sl2:      P1 += 1;\n\t"
+"        %0 = P0;\n\t"
+       : "=&d" (pitch[0])
+       : "a" (corr16), "a" (ener16), "a" (end+1-start), "d" (start) 
+       : "P0", "P1", "I0", "I1", "R0", "R1", "R2", "R3", "R4", "R5"
+#if (__GNUC__ == 4)
+         , "LC1"
+#endif
+       );
+
+      }
+      else {
+	for (i=start;i<=end;i++)
+	  {
+	    spx_word16_t tmp = MULT16_16_16(corr16[i-start],corr16[i-start]);
+	    /* Instead of dividing the tmp by the energy, we multiply on the other side */
+	    if (MULT16_16(tmp,best_ener[N-1])>MULT16_16(best_score[N-1],ADD16(1,ener16[i-start])))
+	      {
+		/* We can safely put it last and then check */
+		best_score[N-1]=tmp;
+		best_ener[N-1]=ener16[i-start]+1;
+		pitch[N-1]=i;
+		/* Check if it comes in front of others */
+		for (j=0;j<N-1;j++)
+		  {
+		    if (MULT16_16(tmp,best_ener[j])>MULT16_16(best_score[j],ADD16(1,ener16[i-start])))
+		      {
+			for (k=N-1;k>j;k--)
+			  {
+			    best_score[k]=best_score[k-1];
+			    best_ener[k]=best_ener[k-1];
+			    pitch[k]=pitch[k-1];
+			  }
+			best_score[j]=tmp;
+			best_ener[j]=ener16[i-start]+1;
+			pitch[j]=i;
+			break;
+		      }
+		  }
+	      }
+	  }
+      }
+   }
+
+   /* Compute open-loop gain */
+   if (gain)
+   {
+       for (j=0;j<N;j++)
+       {
+          spx_word16_t g;
+          i=pitch[j];
+          g = DIV32(corr[i-start], 10+SHR32(MULT16_16(spx_sqrt(e0),spx_sqrt(energy[i-start])),6));
+          /* FIXME: g = max(g,corr/energy) */
+                   if (g<0)
+                   g = 0;
+             gain[j]=g;
+       }
+   }
+}
+#endif
+
+#define OVERRIDE_PITCH_GAIN_SEARCH_3TAP_VQ
+#ifdef OVERRIDE_PITCH_GAIN_SEARCH_3TAP_VQ
+static int pitch_gain_search_3tap_vq(
+  const signed char *gain_cdbk,
+  int                gain_cdbk_size,
+  spx_word16_t      *C16,
+  spx_word16_t       max_gain
+)
+{
+  const signed char *ptr=gain_cdbk;
+  int                best_cdbk=0;
+  spx_word32_t       best_sum=-VERY_LARGE32;
+  spx_word32_t       sum=0;
+  spx_word16_t       g[3];
+  spx_word16_t       pitch_control=64;
+  spx_word16_t       gain_sum;
+  int                i;
+
+      /* fast asm version of VQ codebook search */
+
+      __asm__ __volatile__
+      (
+
+"        P0 = %2;\n\t"                     /* P0: ptr to gain_cdbk */
+"        L1 = 0;\n\t"                      /* no circ addr for L1  */
+"        %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]             */
+"          R3  = B [P0++] (X);\n\t"        /* R3: g[1]             */
+"          R4  = B [P0++] (X);\n\t"        /* R4: g[2]             */
+"          R2 += 32;\n\t"
+"          R3 += 32;\n\t"
+"          R4 += 32;\n\t"
+
+"          R0  = B [P0++] (X);\n\t"              
+"          B0  = R0;\n\t"                  /* BO: gain_sum         */
+          
+           /* compute_pitch_error() -------------------------------*/
+
+"          I1 = %3;\n\t"                   /* I1: ptr to C         */
+"          A0 = 0;\n\t"
+         
+"          R0.L = W[I1++];\n\t"
+"          R1.L = R2.L*R5.L (IS);\n\t"
+"          A0 += R1.L*R0.L (IS) || R0.L = W[I1++];\n\t"
+         
+"          R1.L = R3.L*R5.L (IS);\n\t"
+"          A0 += R1.L*R0.L (IS) || R0.L = W[I1++];\n\t"
+         
+"          R1.L = R4.L*R5.L (IS);\n\t"
+"          A0 += R1.L*R0.L (IS) || R0.L = W[I1++];\n\t"
+         
+"          R1.L = R2.L*R3.L (IS);\n\t"
+"          A0 -= R1.L*R0.L (IS) || R0.L = W[I1++];\n\t"
+
+"          R1.L = R4.L*R3.L (IS);\n\t"
+"          A0 -= R1.L*R0.L (IS) || R0.L = W[I1++];\n\t"
+         
+"          R1.L = R4.L*R2.L (IS);\n\t"
+"          A0 -= R1.L*R0.L (IS) || R0.L = W[I1++];\n\t"
+         
+"          R1.L = R2.L*R2.L (IS);\n\t"
+"          A0 -= R1.L*R0.L (IS) || R0.L = W[I1++];\n\t"
+
+"          R1.L = R3.L*R3.L (IS);\n\t"
+"          A0 -= R1.L*R0.L (IS) || R0.L = W[I1++];\n\t"
+         
+"          R1.L = R4.L*R4.L (IS);\n\t"
+"          R0 = (A0 -= R1.L*R0.L) (IS);\n\t"
+
+/*
+    Re-arrange the if-then to code efficiently on the Blackfin:
+
+      if (sum>best_sum && gain_sum<=max_gain)   ------ (1)
+
+      if (sum>best_sum && !(gain_sum>max_gain)) ------ (2)
+
+      if (max_gain<=gain_sum) {                 ------ (3)
+      sum = -VERY_LARGE32;
+      }
+      if (best_sum<=sum)
+
+    The blackin cc instructions are all of the form:
+
+      cc = x < y (or cc = x <= y)
+*/
+"          R1 = B0\n\t"
+"          R2 = %5\n\t"
+"          R3 = %6\n\t"
+"          cc = R2 <= R1;\n\t" 
+"          if cc R0 = R3;\n\t"
+"          cc = %0 <= R0;\n\t"
+"          if cc %0 = R0;\n\t"
+"          if cc %1 = P1;\n\t"
+
+"pgs2:     P1 += 1;\n\t"
+   
+       : "=&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", 
+         "P1", "I1", "L1", "A0", "B0"
+#if (__GNUC__ == 4)
+         , "LC1"
+#endif
+       );
+
+  return best_cdbk;
+}
+#endif
+
diff --git a/3rdparty/speex/libspeex/ltp_sse.h b/3rdparty/speex/libspeex/ltp_sse.h
new file mode 100644
index 0000000..bed6eaa
--- /dev/null
+++ b/3rdparty/speex/libspeex/ltp_sse.h
@@ -0,0 +1,92 @@
+/* Copyright (C) 2002 Jean-Marc Valin */
+/**
+   @file ltp_sse.h
+   @brief Long-Term Prediction functions (SSE version)
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <xmmintrin.h>
+
+#define OVERRIDE_INNER_PROD
+float inner_prod(const float *a, const float *b, int len)
+{
+   int i;
+   float ret;
+   __m128 sum = _mm_setzero_ps();
+   for (i=0;i<(len>>2);i+=2)
+   {
+      sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(a+0), _mm_loadu_ps(b+0)));
+      sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(a+4), _mm_loadu_ps(b+4)));
+      a += 8;
+      b += 8;
+   }
+   sum = _mm_add_ps(sum, _mm_movehl_ps(sum, sum));
+   sum = _mm_add_ss(sum, _mm_shuffle_ps(sum, sum, 0x55));
+   _mm_store_ss(&ret, sum);
+   return ret;
+}
+
+#define OVERRIDE_PITCH_XCORR
+void pitch_xcorr(const float *_x, const float *_y, float *corr, int len, int nb_pitch, char *stack)
+{
+   int i, offset;
+   VARDECL(__m128 *x);
+   VARDECL(__m128 *y);
+   int N, L;
+   N = len>>2;
+   L = nb_pitch>>2;
+   ALLOC(x, N, __m128);
+   ALLOC(y, N+L, __m128);
+   for (i=0;i<N;i++)
+      x[i] = _mm_loadu_ps(_x+(i<<2));
+   for (offset=0;offset<4;offset++)
+   {
+      for (i=0;i<N+L;i++)
+         y[i] = _mm_loadu_ps(_y+(i<<2)+offset);
+      for (i=0;i<L;i++)
+      {
+         int j;
+         __m128 sum, *xx, *yy;
+         sum = _mm_setzero_ps();
+         yy = y+i;
+         xx = x;
+         for (j=0;j<N;j+=2)
+         {
+            sum = _mm_add_ps(sum, _mm_mul_ps(xx[0], yy[0]));
+            sum = _mm_add_ps(sum, _mm_mul_ps(xx[1], yy[1]));
+            xx += 2;
+            yy += 2;
+         }
+         sum = _mm_add_ps(sum, _mm_movehl_ps(sum, sum));
+         sum = _mm_add_ss(sum, _mm_shuffle_ps(sum, sum, 0x55));
+         _mm_store_ss(corr+nb_pitch-1-(i<<2)-offset, sum);
+      }
+   }
+}
diff --git a/3rdparty/speex/libspeex/math_approx.c b/3rdparty/speex/libspeex/math_approx.c
new file mode 100644
index 0000000..21af766
--- /dev/null
+++ b/3rdparty/speex/libspeex/math_approx.c
@@ -0,0 +1,291 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: math_approx.c
+   Various math approximation functions for Speex
+
+   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 "math_approx.h"
+#include "misc.h"
+
+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;
+}
+
+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
+
+/* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25723*x^3 (for .25 < x < 1) */
+/*#define C0 3634
+#define C1 21173
+#define C2 -12627
+#define C3 4215*/
+
+/* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25659*x^3 (for .25 < x < 1) */
+#define C0 3634
+#define C1 21173
+#define C2 -12627
+#define C3 4204
+
+spx_word16_t spx_sqrt(spx_word32_t x)
+{
+   int k;
+   spx_word32_t rt;
+   k = spx_ilog4(x)-6;
+   x = VSHR32(x, (k<<1));
+   rt = ADD16(C0, MULT16_16_Q14(x, ADD16(C1, MULT16_16_Q14(x, ADD16(C2, MULT16_16_Q14(x, (C3)))))));
+   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
+
+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
+
+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))))))));
+}
+
+spx_word16_t spx_cos_norm(spx_word32_t x)
+{
+   x = x&0x0001ffff;
+   if (x>SHL32(EXTEND32(1), 16))
+      x = SUB32(SHL32(EXTEND32(1), 17),x);
+   if (x&0x00007fff)
+   {
+      if (x<SHL32(EXTEND32(1), 15))
+      {
+         return _spx_cos_pi_2(EXTRACT16(x));
+      } else {
+         return NEG32(_spx_cos_pi_2(EXTRACT16(65536-x)));
+      }
+   } else {
+      if (x&0x0000ffff)
+         return 0;
+      else if (x&0x0001ffff)
+         return -32767;
+      else
+         return 32767;
+   }
+}
+
+/*
+ K0 = 1
+ K1 = log(2)
+ K2 = 3-4*log(2)
+ K3 = 3*log(2) - 2
+*/
+#define D0 16384
+#define D1 11356
+#define D2 3726
+#define D3 1301
+/* Input in Q11 format, output in Q16 */
+static spx_word32_t spx_exp2(spx_word16_t x)
+{
+   int integer;
+   spx_word16_t frac;
+   integer = SHR16(x,11);
+   if (integer>14)
+      return 0x7fffffff;
+   else if (integer < -15)
+      return 0;
+   frac = SHL16(x-SHL16(integer,11),3);
+   frac = ADD16(D0, MULT16_16_Q14(frac, ADD16(D1, MULT16_16_Q14(frac, ADD16(D2 , MULT16_16_Q14(D3,frac))))));
+   return VSHR32(EXTEND32(frac), -integer-2);
+}
+
+/* Input in Q11 format, output in Q16 */
+spx_word32_t spx_exp(spx_word16_t x)
+{
+   if (x>21290)
+      return 0x7fffffff;
+   else if (x<-21290)
+      return 0;
+   else
+      return spx_exp2(MULT16_16_P14(23637,x));
+}
+#define M1 32767
+#define M2 -21
+#define M3 -11943
+#define M4 4936
+
+static inline spx_word16_t spx_atan01(spx_word16_t x)
+{
+   return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x)))))));
+}
+
+/* Input in Q15, output in Q14 */
+spx_word16_t spx_atan(spx_word32_t x)
+{
+   if (x <= 32767)
+   {
+      return SHR16(spx_atan01(x),1);
+   } else {
+      int e = spx_ilog2(x);
+      if (e>=29)
+         return 25736;
+      x = DIV32_16(SHL32(EXTEND32(32767),29-e), EXTRACT16(SHR32(x, e-14)));
+      return SUB16(25736, SHR16(spx_atan01(x),1));
+   }
+}
+#else
+
+#ifndef M_PI
+#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
+spx_word16_t spx_cos(spx_word16_t x)
+{
+   if (x<SPX_PI_2)
+   {
+      x *= x;
+      return C1 + x*(C2+x*(C3+C4*x));
+   } else {
+      x = M_PI-x;
+      x *= x;
+      return NEG16(C1 + x*(C2+x*(C3+C4*x)));
+   }
+}
+
+#endif
diff --git a/3rdparty/speex/libspeex/math_approx.h b/3rdparty/speex/libspeex/math_approx.h
new file mode 100644
index 0000000..49cfda6
--- /dev/null
+++ b/3rdparty/speex/libspeex/math_approx.h
@@ -0,0 +1,62 @@
+/* Copyright (C) 2002 Jean-Marc Valin */
+/**
+   @file math_approx.h
+   @brief Various math approximation functions for Speex
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MATH_APPROX_H
+#define MATH_APPROX_H
+
+#include "misc.h"
+
+spx_word16_t spx_cos(spx_word16_t x);
+spx_int16_t spx_ilog2(spx_uint32_t x);
+spx_int16_t spx_ilog4(spx_uint32_t x);
+#ifdef FIXED_POINT
+spx_word16_t spx_sqrt(spx_word32_t x);
+spx_word16_t spx_acos(spx_word16_t x);
+spx_word32_t spx_exp(spx_word16_t x);
+spx_word16_t spx_cos_norm(spx_word32_t x);
+
+/* Input in Q15, output in Q14 */
+spx_word16_t spx_atan(spx_word32_t x);
+
+#else
+
+#define spx_sqrt sqrt
+#define spx_acos acos
+#define spx_exp exp
+#define spx_cos_norm(x) (cos((.5f*M_PI)*(x)))
+#define spx_atan atan
+
+#endif
+
+#endif
diff --git a/3rdparty/speex/libspeex/mdf.c b/3rdparty/speex/libspeex/mdf.c
new file mode 100644
index 0000000..bc68f91
--- /dev/null
+++ b/3rdparty/speex/libspeex/mdf.c
@@ -0,0 +1,1176 @@
+/* Copyright (C) 2003-2006 Jean-Marc Valin
+
+   File: mdf.c
+   Echo canceller based on the MDF algorithm (see below)
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+   1. Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+   DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+   The echo canceller is based on the MDF algorithm described in:
+
+   J. S. Soo, K. K. Pang Multidelay block frequency adaptive filter, 
+   IEEE Trans. Acoust. Speech Signal Process., Vol. ASSP-38, No. 2, 
+   February 1990.
+   
+   We use the Alternatively Updated MDF (AUMDF) variant. Robustness to 
+   double-talk is achieved using a variable learning rate as described in:
+   
+   Valin, J.-M., On Adjusting the Learning Rate in Frequency Domain Echo 
+   Cancellation With Double-Talk. To appear in IEEE Transactions on Audio,
+   Speech and Language Processing, 2006.
+   http://people.xiph.org/~jm/papers/valin_taslp2006.pdf
+   
+   There is no explicit double-talk detection, but a continuous variation
+   in the learning rate based on residual echo, double-talk and background
+   noise.
+   
+   About the fixed-point version:
+   All the signals are represented with 16-bit words. The filter weights 
+   are represented with 32-bit words, but only the top 16 bits are used
+   in most cases. The lower 16 bits are completely unreliable (due to the
+   fact that the update is done only on the top bits), but help in the
+   adaptation -- probably by removing a "threshold effect" due to
+   quantization (rounding going to zero) when the gradient is small.
+   
+   Another kludge that seems to work good: when performing the weight
+   update, we only move half the way toward the "goal" this seems to
+   reduce the effect of quantization noise in the update phase. This
+   can be seen as applying a gradient descent on a "soft constraint"
+   instead of having a hard constraint.
+   
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "misc.h"
+#include "speex/speex_echo.h"
+#include "fftwrap.h"
+#include "pseudofloat.h"
+#include "math_approx.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#ifdef FIXED_POINT
+#define WEIGHT_SHIFT 11
+#define NORMALIZE_SCALEDOWN 5
+#define NORMALIZE_SCALEUP 3
+#else
+#define WEIGHT_SHIFT 0
+#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 = {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 = .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 */
+   int window_size;
+   int M;
+   int cancel_count;
+   int adapted;
+   int saturated;
+   int screwed_up;
+   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 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_word16_t *Y;      /* scratch */
+   spx_word16_t *E;
+   spx_word32_t *PHI;    /* scratch */
+   spx_word32_t *W;      /* (Background) filter weights */
+#ifdef TWO_PATH
+   spx_word16_t *foreground; /* Foreground filter weights */
+   spx_word32_t  Davg1;  /* 1st recursive average of the residual power difference */
+   spx_word32_t  Davg2;  /* 2nd recursive average of the residual power difference */
+   spx_float_t   Dvar1;  /* Estimated variance of 1st estimator */
+   spx_float_t   Dvar2;  /* Estimated variance of 2nd estimator */
+#endif
+   spx_word32_t *power;  /* Power of the far-end signal */
+   spx_float_t  *power_1;/* Inverse power of far-end */
+   spx_word16_t *wtmp;   /* scratch */
+#ifdef FIXED_POINT
+   spx_word16_t *wtmp2;  /* 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_word16_t *window;
+   spx_word16_t *prop;
+   void *fft_table;
+   spx_word16_t memX, memD, memE;
+   spx_word16_t preemph;
+   spx_word16_t notch_radius;
+   spx_mem_t notch_mem[2];
+
+   /* NOTE: If you only use speex_echo_cancel() and want to save some memory, remove this */
+   spx_int16_t *play_buf;
+   int play_buf_pos;
+   int play_buf_started;
+};
+
+static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius, spx_word16_t *out, int len, spx_mem_t *mem)
+{
+   int i;
+   spx_word16_t den2;
+#ifdef FIXED_POINT
+   den2 = MULT16_16_Q15(radius,radius) + MULT16_16_Q15(QCONST16(.7,15),MULT16_16_Q15(32767-radius,32767-radius));
+#else
+   den2 = radius*radius + .7*(1-radius)*(1-radius);
+#endif   
+   /*printf ("%d %d %d %d %d %d\n", num[0], num[1], num[2], den[0], den[1], den[2]);*/
+   for (i=0;i<len;i++)
+   {
+      spx_word16_t vin = in[i];
+      spx_word32_t vout = mem[0] + SHL32(EXTEND32(vin),15);
+#ifdef FIXED_POINT
+      mem[0] = mem[1] + SHL32(SHL32(-EXTEND32(vin),15) + MULT16_32_Q15(radius,vout),1);
+#else
+      mem[0] = mem[1] + 2*(-vin + radius*vout);
+#endif
+      mem[1] = SHL32(EXTEND32(vin),15) - MULT16_32_Q15(den2,vout);
+      out[i] = SATURATE32(PSHR32(MULT16_32_Q15(radius,vout),15),32767);
+   }
+}
+
+/* This inner product is slightly different from the codec version because of fixed-point */
+static inline spx_word32_t mdf_inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len)
+{
+   spx_word32_t sum=0;
+   len >>= 1;
+   while(len--)
+   {
+      spx_word32_t part=0;
+      part = MAC16_16(part,*x++,*y++);
+      part = MAC16_16(part,*x++,*y++);
+      /* HINT: If you had a 40-bit accumulator, you could shift only at the end */
+      sum = ADD32(sum,SHR32(part,6));
+   }
+   return sum;
+}
+
+/** Compute power spectrum of a half-complex (packed) vector */
+static inline void power_spectrum(const spx_word16_t *X, spx_word32_t *ps, int N)
+{
+   int i, j;
+   ps[0]=MULT16_16(X[0],X[0]);
+   for (i=1,j=1;i<N-1;i+=2,j++)
+   {
+      ps[j] =  MULT16_16(X[i],X[i]) + MULT16_16(X[i+1],X[i+1]);
+   }
+   ps[j]=MULT16_16(X[i],X[i]);
+}
+
+/** Compute cross-power spectrum of a half-complex (packed) vectors and add to acc */
+#ifdef FIXED_POINT
+static inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t *Y, spx_word16_t *acc, int N, int M)
+{
+   int i,j;
+   spx_word32_t tmp1=0,tmp2=0;
+   for (j=0;j<M;j++)
+   {
+      tmp1 = MAC16_16(tmp1, X[j*N],TOP16(Y[j*N]));
+   }
+   acc[0] = PSHR32(tmp1,WEIGHT_SHIFT);
+   for (i=1;i<N-1;i+=2)
+   {
+      tmp1 = tmp2 = 0;
+      for (j=0;j<M;j++)
+      {
+         tmp1 = SUB32(MAC16_16(tmp1, X[j*N+i],TOP16(Y[j*N+i])), MULT16_16(X[j*N+i+1],TOP16(Y[j*N+i+1])));
+         tmp2 = MAC16_16(MAC16_16(tmp2, X[j*N+i+1],TOP16(Y[j*N+i])), X[j*N+i], TOP16(Y[j*N+i+1]));
+      }
+      acc[i] = PSHR32(tmp1,WEIGHT_SHIFT);
+      acc[i+1] = PSHR32(tmp2,WEIGHT_SHIFT);
+   }
+   tmp1 = tmp2 = 0;
+   for (j=0;j<M;j++)
+   {
+      tmp1 = MAC16_16(tmp1, X[(j+1)*N-1],TOP16(Y[(j+1)*N-1]));
+   }
+   acc[N-1] = PSHR32(tmp1,WEIGHT_SHIFT);
+}
+static inline void spectral_mul_accum16(const spx_word16_t *X, const spx_word16_t *Y, spx_word16_t *acc, int N, int M)
+{
+   int i,j;
+   spx_word32_t tmp1=0,tmp2=0;
+   for (j=0;j<M;j++)
+   {
+      tmp1 = MAC16_16(tmp1, X[j*N],Y[j*N]);
+   }
+   acc[0] = PSHR32(tmp1,WEIGHT_SHIFT);
+   for (i=1;i<N-1;i+=2)
+   {
+      tmp1 = tmp2 = 0;
+      for (j=0;j<M;j++)
+      {
+         tmp1 = SUB32(MAC16_16(tmp1, X[j*N+i],Y[j*N+i]), MULT16_16(X[j*N+i+1],Y[j*N+i+1]));
+         tmp2 = MAC16_16(MAC16_16(tmp2, X[j*N+i+1],Y[j*N+i]), X[j*N+i], Y[j*N+i+1]);
+      }
+      acc[i] = PSHR32(tmp1,WEIGHT_SHIFT);
+      acc[i+1] = PSHR32(tmp2,WEIGHT_SHIFT);
+   }
+   tmp1 = tmp2 = 0;
+   for (j=0;j<M;j++)
+   {
+      tmp1 = MAC16_16(tmp1, X[(j+1)*N-1],Y[(j+1)*N-1]);
+   }
+   acc[N-1] = PSHR32(tmp1,WEIGHT_SHIFT);
+}
+
+#else
+static inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t *Y, spx_word16_t *acc, int N, int M)
+{
+   int i,j;
+   for (i=0;i<N;i++)
+      acc[i] = 0;
+   for (j=0;j<M;j++)
+   {
+      acc[0] += X[0]*Y[0];
+      for (i=1;i<N-1;i+=2)
+      {
+         acc[i] += (X[i]*Y[i] - X[i+1]*Y[i+1]);
+         acc[i+1] += (X[i+1]*Y[i] + X[i]*Y[i+1]);
+      }
+      acc[i] += X[i]*Y[i];
+      X += N;
+      Y += N;
+   }
+}
+#define spectral_mul_accum16 spectral_mul_accum
+#endif
+
+/** Compute weighted cross-power spectrum of a half-complex (packed) vector with conjugate */
+static inline void weighted_spectral_mul_conj(const spx_float_t *w, const spx_float_t p, const spx_word16_t *X, const spx_word16_t *Y, spx_word32_t *prod, int N)
+{
+   int i, j;
+   spx_float_t W;
+   W = FLOAT_AMULT(p, w[0]);
+   prod[0] = FLOAT_MUL32(W,MULT16_16(X[0],Y[0]));
+   for (i=1,j=1;i<N-1;i+=2,j++)
+   {
+      W = FLOAT_AMULT(p, w[j]);
+      prod[i] = FLOAT_MUL32(W,MAC16_16(MULT16_16(X[i],Y[i]), X[i+1],Y[i+1]));
+      prod[i+1] = FLOAT_MUL32(W,MAC16_16(MULT16_16(-X[i+1],Y[i]), X[i],Y[i+1]));
+   }
+   W = FLOAT_AMULT(p, w[j]);
+   prod[i] = FLOAT_MUL32(W,MULT16_16(X[i],Y[i]));
+}
+
+static inline void mdf_adjust_prop(const spx_word32_t *W, int N, int M, spx_word16_t *prop)
+{
+   int i, j;
+   spx_word16_t max_sum = 1;
+   spx_word32_t prop_sum = 1;
+   for (i=0;i<M;i++)
+   {
+      spx_word32_t tmp = 1;
+      for (j=0;j<N;j++)
+         tmp += MULT16_16(EXTRACT16(SHR32(W[i*N+j],18)), EXTRACT16(SHR32(W[i*N+j],18)));
+#ifdef FIXED_POINT
+      /* Just a security in case an overflow were to occur */
+      tmp = MIN32(ABS32(tmp), 536870912);
+#endif
+      prop[i] = spx_sqrt(tmp);
+      if (prop[i] > max_sum)
+         max_sum = prop[i];
+   }
+   for (i=0;i<M;i++)
+   {
+      prop[i] += MULT16_16_Q15(QCONST16(.1f,15),max_sum);
+      prop_sum += EXTEND32(prop[i]);
+   }
+   for (i=0;i<M;i++)
+   {
+      prop[i] = DIV32(MULT16_16(QCONST16(.99f,15), prop[i]),prop_sum);
+      /*printf ("%f ", prop[i]);*/
+   }
+   /*printf ("\n");*/
+}
+
+#ifdef DUMP_ECHO_CANCEL_DATA
+#include <stdio.h>
+static FILE *rFile=NULL, *pFile=NULL, *oFile=NULL;
+
+static void dump_audio(const spx_int16_t *rec, const spx_int16_t *play, const spx_int16_t *out, int len)
+{
+   if (!(rFile && pFile && oFile))
+   {
+      speex_error("Dump files not open");
+   }
+   fwrite(rec, sizeof(spx_int16_t), len, rFile);
+   fwrite(play, sizeof(spx_int16_t), len, pFile);
+   fwrite(out, sizeof(spx_int16_t), len, oFile);
+}
+#endif
+
+/** Creates a new echo canceller state */
+SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
+{
+   int i,N,M;
+   SpeexEchoState *st = (SpeexEchoState *)speex_alloc(sizeof(SpeexEchoState));
+
+#ifdef DUMP_ECHO_CANCEL_DATA
+   if (rFile || pFile || oFile)
+      speex_error("Opening dump files twice");
+   rFile = fopen("aec_rec.sw", "w");
+   pFile = fopen("aec_play.sw", "w");
+   oFile = fopen("aec_out.sw", "w");
+#endif
+   
+   st->frame_size = frame_size;
+   st->window_size = 2*frame_size;
+   N = st->window_size;
+   M = st->M = (filter_length+st->frame_size-1)/frame_size;
+   st->cancel_count=0;
+   st->sum_adapt = 0;
+   st->saturated = 0;
+   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
+   st->beta0 = DIV32_16(SHL32(EXTEND32(st->frame_size), 16), st->sampling_rate);
+   st->beta_max = DIV32_16(SHL32(EXTEND32(st->frame_size), 14), st->sampling_rate);
+#else
+   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->input = (spx_word16_t*)speex_alloc(st->frame_size*sizeof(spx_word16_t));
+   st->y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
+   st->last_y = (spx_word16_t*)speex_alloc(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));
+#ifdef TWO_PATH
+   st->foreground = (spx_word16_t*)speex_alloc(M*N*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));
+   st->window = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
+   st->prop = (spx_word16_t*)speex_alloc(M*sizeof(spx_word16_t));
+   st->wtmp = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
+#ifdef FIXED_POINT
+   st->wtmp2 = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
+   for (i=0;i<N>>1;i++)
+   {
+      st->window[i] = (16383-SHL16(spx_cos(DIV32_16(MULT16_16(25736,i<<1),N)),1));
+      st->window[N-i-1] = st->window[i];
+   }
+#else
+   for (i=0;i<N;i++)
+      st->window[i] = .5-.5*cos(2*M_PI*i/N);
+#endif
+   for (i=0;i<=st->frame_size;i++)
+      st->power_1[i] = FLOAT_ONE;
+   for (i=0;i<N*M;i++)
+      st->W[i] = 0;
+   {
+      spx_word32_t sum = 0;
+      /* Ratio of ~10 between adaptation rate of first and last block */
+      spx_word16_t decay = SHR32(spx_exp(NEG16(DIV32_16(QCONST16(2.4,11),M))),1);
+      st->prop[0] = QCONST16(.7, 15);
+      sum = EXTEND32(st->prop[0]);
+      for (i=1;i<M;i++)
+      {
+         st->prop[i] = MULT16_16_Q15(st->prop[i-1], decay);
+         sum = ADD32(sum, EXTEND32(st->prop[i]));
+      }
+      for (i=M-1;i>=0;i--)
+      {
+         st->prop[i] = DIV32(MULT16_16(QCONST16(.8,15), st->prop[i]),sum);
+      }
+   }
+   
+   st->memX=st->memD=st->memE=0;
+   st->preemph = QCONST16(.9,15);
+   if (st->sampling_rate<12000)
+      st->notch_radius = QCONST16(.9, 15);
+   else if (st->sampling_rate<24000)
+      st->notch_radius = QCONST16(.982, 15);
+   else
+      st->notch_radius = QCONST16(.992, 15);
+
+   st->notch_mem[0] = st->notch_mem[1] = 0;
+   st->adapted = 0;
+   st->Pey = st->Pyy = FLOAT_ONE;
+   
+#ifdef TWO_PATH
+   st->Davg1 = st->Davg2 = 0;
+   st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
+#endif
+   
+   st->play_buf = (spx_int16_t*)speex_alloc((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)
+{
+   int i, M, N;
+   st->cancel_count=0;
+   st->screwed_up = 0;
+   N = st->window_size;
+   M = st->M;
+   for (i=0;i<N*M;i++)
+      st->W[i] = 0;
+#ifdef TWO_PATH
+   for (i=0;i<N*M;i++)
+      st->foreground[i] = 0;
+#endif
+   for (i=0;i<N*(M+1);i++)
+      st->X[i] = 0;
+   for (i=0;i<=st->frame_size;i++)
+   {
+      st->power[i] = 0;
+      st->power_1[i] = FLOAT_ONE;
+      st->Eh[i] = 0;
+      st->Yh[i] = 0;
+   }
+   for (i=0;i<st->frame_size;i++)
+   {
+      st->last_y[i] = 0;
+   }
+   for (i=0;i<N;i++)
+   {
+      st->E[i] = 0;
+      st->x[i] = 0;
+   }
+   st->notch_mem[0] = st->notch_mem[1] = 0;
+   st->memX=st->memD=st->memE=0;
+
+   st->saturated = 0;
+   st->adapted = 0;
+   st->sum_adapt = 0;
+   st->Pey = st->Pyy = FLOAT_ONE;
+#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)
+{
+   spx_fft_destroy(st->fft_table);
+
+   speex_free(st->e);
+   speex_free(st->x);
+   speex_free(st->input);
+   speex_free(st->y);
+   speex_free(st->last_y);
+   speex_free(st->Yf);
+   speex_free(st->Rf);
+   speex_free(st->Xf);
+   speex_free(st->Yh);
+   speex_free(st->Eh);
+
+   speex_free(st->X);
+   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);
+   speex_free(st->window);
+   speex_free(st->prop);
+   speex_free(st->wtmp);
+#ifdef FIXED_POINT
+   speex_free(st->wtmp2);
+#endif
+   speex_free(st->play_buf);
+   speex_free(st);
+   
+#ifdef DUMP_ECHO_CANCEL_DATA
+   fclose(rFile);
+   fclose(pFile);
+   fclose(oFile);
+   rFile = pFile = oFile = NULL;
+#endif
+}
+
+void 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_cancellation(st, rec, st->play_buf, out);
+      st->play_buf_pos -= st->frame_size;
+      for (i=0;i<st->play_buf_pos;i++)
+         st->play_buf[i] = st->play_buf[i+st->frame_size];
+   } else {
+      speex_warning("No playback frame available (your application is buggy and/or got xruns)");
+      if (st->play_buf_pos!=0)
+      {
+         speex_warning("internal playback buffer corruption?");
+         st->play_buf_pos = 0;
+      }
+      for (i=0;i<st->frame_size;i++)
+         out[i] = rec[i];
+   }
+}
+
+void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play)
+{
+   /*speex_warning_int("playback with fill level ", st->play_buf_pos/st->frame_size);*/
+   if (!st->play_buf_started)
+   {
+      speex_warning("discarded first playback frame");
+      return;
+   }
+   if (st->play_buf_pos<=PLAYBACK_DELAY*st->frame_size)
+   {
+      int i;
+      for (i=0;i<st->frame_size;i++)
+         st->play_buf[st->play_buf_pos+i] = play[i];
+      st->play_buf_pos += st->frame_size;
+      if (st->play_buf_pos <= (PLAYBACK_DELAY-1)*st->frame_size)
+      {
+         speex_warning("Auto-filling the buffer (your application is buggy and/or got xruns)");
+         for (i=0;i<st->frame_size;i++)
+            st->play_buf[st->play_buf_pos+i] = play[i];
+         st->play_buf_pos += st->frame_size;
+      }
+   } else {
+      speex_warning("Had to discard a playback frame (your application is buggy and/or got xruns)");
+   }
+}
+
+/** Performs echo cancellation on a frame */
+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)
+{
+   speex_echo_cancellation(st, in, far_end, out);
+}
+
+/** Performs echo cancellation on a frame (deprecated, last arg now ignored) */
+void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out)
+{
+   int i,j;
+   int N,M;
+   spx_word32_t Syy,See,Sxx,Sdd, Sff;
+#ifdef TWO_PATH
+   spx_word32_t Dbf;
+   int update_foreground;
+#endif
+   spx_word32_t Sey;
+   spx_word16_t ss, ss_1;
+   spx_float_t Pey = FLOAT_ONE, Pyy=FLOAT_ONE;
+   spx_float_t alpha, alpha_1;
+   spx_word16_t RER;
+   spx_word32_t tmp32;
+   
+   N = st->window_size;
+   M = st->M;
+   st->cancel_count++;
+#ifdef FIXED_POINT
+   ss=DIV32_16(11469,M);
+   ss_1 = SUB16(32767,ss);
+#else
+   ss=.35/M;
+   ss_1 = 1-ss;
+#endif
+
+   /* Apply a notch filter to make sure DC doesn't end up causing problems */
+   filter_dc_notch16(in, st->notch_radius, st->input, st->frame_size, st->notch_mem);
+   /* Copy input data to buffer and apply pre-emphasis */
+   for (i=0;i<st->frame_size;i++)
+   {
+      spx_word32_t tmp32;
+      tmp32 = SUB32(EXTEND32(far_end[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memX)));
+#ifdef FIXED_POINT
+      /* If saturation occurs here, we need to freeze adaptation for M+1 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[i+st->frame_size] = EXTRACT16(tmp32);
+      st->memX = far_end[i];
+      
+      tmp32 = SUB32(EXTEND32(st->input[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memD)));
+#ifdef FIXED_POINT
+      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->memD = st->input[i];
+      st->input[i] = tmp32;
+   }
+
+   /* Shift memory: this could be optimized eventually*/
+   for (j=M-1;j>=0;j--)
+   {
+      for (i=0;i<N;i++)
+         st->X[(j+1)*N+i] = st->X[j*N+i];
+   }
+
+   /* Convert x (far end) to frequency domain */
+   spx_fft(st->fft_table, st->x, &st->X[0]);
+   for (i=0;i<N;i++)
+      st->last_y[i] = st->x[i];
+   Sxx = mdf_inner_prod(st->x+st->frame_size, st->x+st->frame_size, st->frame_size);
+   for (i=0;i<st->frame_size;i++)
+      st->x[i] = st->x[i+st->frame_size];
+   /* From here on, the top part of x is used as scratch space */
+   
+#ifdef TWO_PATH
+   /* Compute foreground filter */
+   spectral_mul_accum16(st->X, st->foreground, st->Y, N, M);   
+   spx_ifft(st->fft_table, st->Y, st->e);
+   for (i=0;i<st->frame_size;i++)
+      st->x[i+st->frame_size] = SUB16(st->input[i], st->e[i+st->frame_size]);
+   Sff = mdf_inner_prod(st->x+st->frame_size, st->x+st->frame_size, st->frame_size);
+#endif
+   
+   /* Adjust proportional adaption rate */
+   mdf_adjust_prop (st->W, N, M, st->prop);
+   /* Compute weight gradient */
+   if (st->saturated == 0)
+   {
+      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], st->E, st->PHI, N);
+         for (i=0;i<N;i++)
+            st->W[j*N+i] = ADD32(st->W[j*N+i], st->PHI[i]);
+         
+      }
+   } else {
+      st->saturated--;
+   }
+   
+   /* Update weight to prevent circular convolution (MDF / AUMDF) */
+   for (j=0;j<M;j++)
+   {
+      /* This is a variant of the Alternatively Updated MDF (AUMDF) */
+      /* Remove the "if" to make this an MDF filter */
+      if (j==0 || st->cancel_count%(M-1) == j-1)
+      {
+#ifdef FIXED_POINT
+         for (i=0;i<N;i++)
+            st->wtmp2[i] = EXTRACT16(PSHR32(st->W[j*N+i],NORMALIZE_SCALEDOWN+16));
+         spx_ifft(st->fft_table, st->wtmp2, st->wtmp);
+         for (i=0;i<st->frame_size;i++)
+         {
+            st->wtmp[i]=0;
+         }
+         for (i=st->frame_size;i<N;i++)
+         {
+            st->wtmp[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;i<N;i++)
+            st->W[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;i<N;i++)
+         {
+            st->wtmp[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);
+
+#ifdef TWO_PATH
+   /* Difference in response, this is used to estimate the variance of our residual power estimate */
+   for (i=0;i<st->frame_size;i++)
+      st->x[i+st->frame_size] = SUB16(st->e[i+st->frame_size], st->y[i+st->frame_size]);
+   Dbf = 10+mdf_inner_prod(st->x+st->frame_size, st->x+st->frame_size, st->frame_size);
+#endif
+
+   for (i=0;i<st->frame_size;i++)
+      st->x[i+st->frame_size] = SUB16(st->input[i], st->y[i+st->frame_size]);
+   See = mdf_inner_prod(st->x+st->frame_size, st->x+st->frame_size, st->frame_size);
+#ifndef TWO_PATH
+   Sff = See;
+#endif
+
+#ifdef TWO_PATH
+   /* Logic for updating the foreground filter */
+   
+   /* For two time windows, compute the mean of the energy difference, as well as the variance */
+   st->Davg1 = ADD32(MULT16_32_Q15(QCONST16(.6f,15),st->Davg1), MULT16_32_Q15(QCONST16(.4f,15),SUB32(Sff,See)));
+   st->Davg2 = ADD32(MULT16_32_Q15(QCONST16(.85f,15),st->Davg2), MULT16_32_Q15(QCONST16(.15f,15),SUB32(Sff,See)));
+   st->Dvar1 = FLOAT_ADD(FLOAT_MULT(VAR1_SMOOTH, st->Dvar1), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.4f,15),Sff), MULT16_32_Q15(QCONST16(.4f,15),Dbf)));
+   st->Dvar2 = FLOAT_ADD(FLOAT_MULT(VAR2_SMOOTH, st->Dvar2), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.15f,15),Sff), MULT16_32_Q15(QCONST16(.15f,15),Dbf)));
+   
+   /* Equivalent float code:
+   st->Davg1 = .6*st->Davg1 + .4*(Sff-See);
+   st->Davg2 = .85*st->Davg2 + .15*(Sff-See);
+   st->Dvar1 = .36*st->Dvar1 + .16*Sff*Dbf;
+   st->Dvar2 = .7225*st->Dvar2 + .0225*Sff*Dbf;
+   */
+   
+   update_foreground = 0;
+   /* Check if we have a statistically significant reduction in the residual echo */
+   /* Note that this is *not* Gaussian, so we need to be careful about the longer tail */
+   if (FLOAT_GT(FLOAT_MUL32U(SUB32(Sff,See),ABS32(SUB32(Sff,See))), FLOAT_MUL32U(Sff,Dbf)))
+      update_foreground = 1;
+   else if (FLOAT_GT(FLOAT_MUL32U(st->Davg1, ABS32(st->Davg1)), FLOAT_MULT(VAR1_UPDATE,(st->Dvar1))))
+      update_foreground = 1;
+   else if (FLOAT_GT(FLOAT_MUL32U(st->Davg2, ABS32(st->Davg2)), FLOAT_MULT(VAR2_UPDATE,(st->Dvar2))))
+      update_foreground = 1;
+   
+   /* Do we update? */
+   if (update_foreground)
+   {
+      st->Davg1 = st->Davg2 = 0;
+      st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
+      /* Copy background filter to foreground filter */
+      for (i=0;i<N*M;i++)
+         st->foreground[i] = EXTRACT16(PSHR32(st->W[i],16));
+      /* Apply a smooth transition so as to not introduce blocking artifacts */
+      for (i=0;i<st->frame_size;i++)
+         st->e[i+st->frame_size] = 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]);
+   } else {
+      int reset_background=0;
+      /* Otherwise, check if the background filter is significantly worse */
+      if (FLOAT_GT(FLOAT_MUL32U(NEG32(SUB32(Sff,See)),ABS32(SUB32(Sff,See))), FLOAT_MULT(VAR_BACKTRACK,FLOAT_MUL32U(Sff,Dbf))))
+         reset_background = 1;
+      if (FLOAT_GT(FLOAT_MUL32U(NEG32(st->Davg1), ABS32(st->Davg1)), FLOAT_MULT(VAR_BACKTRACK,st->Dvar1)))
+         reset_background = 1;
+      if (FLOAT_GT(FLOAT_MUL32U(NEG32(st->Davg2), ABS32(st->Davg2)), FLOAT_MULT(VAR_BACKTRACK,st->Dvar2)))
+         reset_background = 1;
+      if (reset_background)
+      {
+         /* Copy foreground filter to background filter */
+         for (i=0;i<N*M;i++)
+            st->W[i] = SHL32(EXTEND32(st->foreground[i]),16);
+         /* We also need to copy the output so as to get correct adaptation */
+         for (i=0;i<st->frame_size;i++)
+            st->y[i+st->frame_size] = st->e[i+st->frame_size];
+         for (i=0;i<st->frame_size;i++)
+            st->x[i+st->frame_size] = SUB16(st->input[i], st->y[i+st->frame_size]);
+         See = Sff;
+         st->Davg1 = st->Davg2 = 0;
+         st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
+      }
+   }
+#endif
+
+   /* Compute error signal (for the output with de-emphasis) */ 
+   for (i=0;i<st->frame_size;i++)
+   {
+      spx_word32_t tmp_out;
+#ifdef TWO_PATH
+      tmp_out = SUB32(EXTEND32(st->input[i]), EXTEND32(st->e[i+st->frame_size]));
+#else
+      tmp_out = SUB32(EXTEND32(st->input[i]), 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 in the microphone signal */
+      if (in[i] <= -32000 || in[i] >= 32000)
+      {
+         tmp_out = 0;
+         if (st->saturated == 0)
+            st->saturated = 1;
+      }
+      out[i] = (spx_int16_t)tmp_out;
+      st->memE = tmp_out;
+   }
+   
+#ifdef DUMP_ECHO_CANCEL_DATA
+   dump_audio(in, far_end, out, st->frame_size);
+#endif
+   
+   /* Compute error signal (filter update version) */ 
+   for (i=0;i<st->frame_size;i++)
+   {
+      st->e[i] = 0;
+      st->e[i+st->frame_size] = st->x[i+st->frame_size];
+   }
+
+   /* Compute a bunch of correlations */
+   Sey = mdf_inner_prod(st->e+st->frame_size, st->y+st->frame_size, st->frame_size);
+   Syy = mdf_inner_prod(st->y+st->frame_size, st->y+st->frame_size, st->frame_size);
+   Sdd = mdf_inner_prod(st->input, st->input, st->frame_size);
+   
+   /*printf ("%f %f %f %f\n", Sff, See, Syy, Sdd, st->update_cond);*/
+   
+   /* Do some sanity check */
+   if (!(Syy>=0 && Sxx>=0 && See >= 0)
+#ifndef FIXED_POINT
+       || !(Sff < N*1e9 && Syy < N*1e9 && Sxx < N*1e9)
+#endif
+      )
+   {
+      /* Things have gone really bad */
+      st->screwed_up += 50;
+      for (i=0;i<st->frame_size;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));
+
+   /* Convert error to frequency domain */
+   spx_fft(st->fft_table, st->e, st->E);
+   for (i=0;i<st->frame_size;i++)
+      st->y[i] = 0;
+   spx_fft(st->fft_table, st->y, st->Y);
+
+   /* Compute power spectrum of far end (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);
+   
+   /* 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;i<M;i++)
+      {
+         power_spectrum(&st->X[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--)
+   {
+      spx_float_t Eh, Yh;
+      Eh = PSEUDOFLOAT(st->Rf[j] - st->Eh[j]);
+      Yh = PSEUDOFLOAT(st->Yf[j] - st->Yh[j]);
+      Pey = FLOAT_ADD(Pey,FLOAT_MULT(Eh,Yh));
+      Pyy = FLOAT_ADD(Pyy,FLOAT_MULT(Yh,Yh));
+#ifdef FIXED_POINT
+      st->Eh[j] = MAC16_32_Q15(MULT16_32_Q15(SUB16(32767,st->spec_average),st->Eh[j]), st->spec_average, st->Rf[j]);
+      st->Yh[j] = MAC16_32_Q15(MULT16_32_Q15(SUB16(32767,st->spec_average),st->Yh[j]), st->spec_average, st->Yf[j]);
+#else
+      st->Eh[j] = (1-st->spec_average)*st->Eh[j] + st->spec_average*st->Rf[j];
+      st->Yh[j] = (1-st->spec_average)*st->Yh[j] + st->spec_average*st->Yf[j];
+#endif
+   }
+   
+   Pyy = FLOAT_SQRT(Pyy);
+   Pey = FLOAT_DIVU(Pey,Pyy);
+
+   /* Compute correlation updatete rate */
+   tmp32 = MULT16_32_Q15(st->beta0,Syy);
+   if (tmp32 > MULT16_32_Q15(st->beta_max,See))
+      tmp32 = MULT16_32_Q15(st->beta_max,See);
+   alpha = FLOAT_DIV32(tmp32, See);
+   alpha_1 = FLOAT_SUB(FLOAT_ONE, alpha);
+   /* Update correlations (recursive average) */
+   st->Pey = FLOAT_ADD(FLOAT_MULT(alpha_1,st->Pey) , FLOAT_MULT(alpha,Pey));
+   st->Pyy = FLOAT_ADD(FLOAT_MULT(alpha_1,st->Pyy) , FLOAT_MULT(alpha,Pyy));
+   if (FLOAT_LT(st->Pyy, FLOAT_ONE))
+      st->Pyy = FLOAT_ONE;
+   /* We don't really hope to get better than 33 dB (MIN_LEAK-3dB) attenuation anyway */
+   if (FLOAT_LT(st->Pey, FLOAT_MULT(MIN_LEAK,st->Pyy)))
+      st->Pey = FLOAT_MULT(MIN_LEAK,st->Pyy);
+   if (FLOAT_GT(st->Pey, st->Pyy))
+      st->Pey = st->Pyy;
+   /* leak_estimate is the linear regression result */
+   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 (st->leak_estimate > 16383)
+      st->leak_estimate = 32767;
+   else
+      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(st->leak_estimate,Syy);
+   tmp32 = ADD32(SHR32(Sxx,13), ADD32(tmp32, SHL32(tmp32,1)));
+   /* Check for y in e (lower bound on RER) */
+   {
+      spx_float_t bound = PSEUDOFLOAT(Sey);
+      bound = FLOAT_DIVU(FLOAT_MULT(bound, bound), PSEUDOFLOAT(ADD32(1,Syy)));
+      if (FLOAT_GT(bound, PSEUDOFLOAT(See)))
+         tmp32 = See;
+      else if (tmp32 < FLOAT_EXTRACT32(bound))
+         tmp32 = FLOAT_EXTRACT32(bound);
+   }
+   if (tmp32 > SHR32(See,1))
+      tmp32 = SHR32(See,1);
+   RER = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32,See),15));
+#else
+   RER = (.0001*Sxx + 3.*MULT16_32_Q15(st->leak_estimate,Syy)) / See;
+   /* Check for y in e (lower bound on RER) */
+   if (RER < Sey*Sey/(1+See*Syy))
+      RER = Sey*Sey/(1+See*Syy);
+   if (RER > .5)
+      RER = .5;
+#endif
+
+   /* We consider that the filter has had minimal adaptation if the following is true*/
+   if (!st->adapted && st->sum_adapt > QCONST32(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(st->leak_estimate,SHL32(st->Yf[i],3));
+         e = SHL32(st->Rf[i],3)+1;
+#ifdef FIXED_POINT
+         if (r>SHR32(e,1))
+            r = SHR32(e,1);
+#else
+         if (r>.5*e)
+            r = .5*e;
+#endif
+         r = MULT16_32_Q15(QCONST16(.7,15),r) + MULT16_32_Q15(QCONST16(.3,15),(spx_word32_t)(MULT16_32_Q15(RER,e)));
+         /*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 {
+      /* Temporary adaption rate if filter is not yet adapted enough */
+      spx_word16_t adapt_rate=0;
+
+      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);
+#else
+         if (tmp32 > .25*See)
+            tmp32 = .25*See;
+#endif
+         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);
+
+
+      /* How much have we adapted so far? */
+      st->sum_adapt = ADD32(st->sum_adapt,adapt_rate);
+   }
+
+   /* Save residual echo so it can be used by the nonlinear processor */
+   if (st->adapted)
+   {
+      /* If the filter is adapted, take the filtered echo */
+      for (i=0;i<st->frame_size;i++)
+         st->last_y[i] = st->last_y[st->frame_size+i];
+      for (i=0;i<st->frame_size;i++)
+         st->last_y[st->frame_size+i] = in[i]-out[i];
+   } else {
+      /* If filter isn't adapted yet, all we can do is take the far end signal directly */
+      /* moved earlier: for (i=0;i<N;i++)
+      st->last_y[i] = st->x[i];*/
+   }
+
+}
+
+/* Compute spectrum of estimated echo for use in an echo post-filter */
+void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *residual_echo, int len)
+{
+   int i;
+   spx_word16_t leak2;
+   int N;
+   
+   N = st->window_size;
+
+   /* Apply hanning window (should pre-compute it)*/
+   for (i=0;i<N;i++)
+      st->y[i] = MULT16_16_Q15(st->window[i],st->last_y[i]);
+      
+   /* Compute power spectrum of the echo */
+   spx_fft(st->fft_table, st->y, st->Y);
+   power_spectrum(st->Y, 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]);
+   
+}
+
+int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr)
+{
+   switch(request)
+   {
+      
+      case SPEEX_ECHO_GET_FRAME_SIZE:
+         (*(int*)ptr) = st->frame_size;
+         break;
+      case SPEEX_ECHO_SET_SAMPLING_RATE:
+         st->sampling_rate = (*(int*)ptr);
+         st->spec_average = DIV32_16(SHL32(EXTEND32(st->frame_size), 15), st->sampling_rate);
+#ifdef FIXED_POINT
+         st->beta0 = DIV32_16(SHL32(EXTEND32(st->frame_size), 16), st->sampling_rate);
+         st->beta_max = DIV32_16(SHL32(EXTEND32(st->frame_size), 14), st->sampling_rate);
+#else
+         st->beta0 = (2.0f*st->frame_size)/st->sampling_rate;
+         st->beta_max = (.5f*st->frame_size)/st->sampling_rate;
+#endif
+         if (st->sampling_rate<12000)
+            st->notch_radius = QCONST16(.9, 15);
+         else if (st->sampling_rate<24000)
+            st->notch_radius = QCONST16(.982, 15);
+         else
+            st->notch_radius = QCONST16(.992, 15);
+         break;
+      case SPEEX_ECHO_GET_SAMPLING_RATE:
+         (*(int*)ptr) = st->sampling_rate;
+         break;
+      default:
+         speex_warning_int("Unknown speex_echo_ctl request: ", request);
+         return -1;
+   }
+   return 0;
+}
diff --git a/3rdparty/speex/libspeex/medfilter.c b/3rdparty/speex/libspeex/medfilter.c
new file mode 100644
index 0000000..83872e5
--- /dev/null
+++ b/3rdparty/speex/libspeex/medfilter.c
@@ -0,0 +1,97 @@
+/* Copyright (C) 2004 Jean-Marc Valin
+   File medfilter.c
+   Median filter
+
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "medfilter.h"
+#include "misc.h"
+
+MedianFilter *median_filter_new(int N)
+{
+   MedianFilter *f = (MedianFilter*)speex_alloc(sizeof(MedianFilter));
+   f->N = N;
+   f->ids = (int*)speex_alloc(sizeof(int)*N);
+   f->val = (float*)speex_alloc(sizeof(float)*N);
+   f->filled = 0;
+   return f;
+}
+
+void median_filter_update(MedianFilter *f, float val)
+{
+   int i=0;
+   int insert = 0;
+   while (insert<f->filled && f->val[insert] < val)
+   {
+      insert++;
+   }
+   if (f->filled == f->N)
+   {
+      int remove;
+      for (remove=0;remove<f->N;remove++)
+         if (f->ids[remove] == 0)
+            break;
+      if (insert>remove)
+         insert--;
+      if (insert > remove)
+      {
+         for (i=remove;i<insert;i++)
+         {
+            f->val[i] = f->val[i+1];
+            f->ids[i] = f->ids[i+1];
+         }
+      } else if (insert < remove)
+      {
+         for (i=remove;i>insert;i--)
+         {
+            f->val[i] = f->val[i-1];
+            f->ids[i] = f->ids[i-1];
+         }
+      }
+      for (i=0;i<f->filled;i++)
+         f->ids[i]--;
+   } else {
+      for (i=f->filled;i>insert;i--)
+      {
+         f->val[i] = f->val[i-1];
+         f->ids[i] = f->ids[i-1];
+      }
+      f->filled++;
+   }
+   f->val[insert]=val;
+   f->ids[insert]=f->filled-1;
+}
+
+float median_filter_get(MedianFilter *f)
+{
+   return f->val[f->filled>>1];
+}
+
diff --git a/3rdparty/speex/libspeex/medfilter.h b/3rdparty/speex/libspeex/medfilter.h
new file mode 100644
index 0000000..718869c
--- /dev/null
+++ b/3rdparty/speex/libspeex/medfilter.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 2004 Jean-Marc Valin */
+/**
+   @file medfilter.h
+   @brief Median filter
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef MEDFILTER_H
+#define MEDFILTER_H
+
+/** Median filter. */
+typedef struct {
+   int N;
+   int filled;
+   int *ids;
+   float *val;
+} MedianFilter;
+
+MedianFilter *median_filter_new(int N);
+void median_filter_update(MedianFilter *f, float val);
+float median_filter_get(MedianFilter *f);
+
+#endif
diff --git a/3rdparty/speex/libspeex/misc.c b/3rdparty/speex/libspeex/misc.c
new file mode 100644
index 0000000..c7ce7a8
--- /dev/null
+++ b/3rdparty/speex/libspeex/misc.c
@@ -0,0 +1,194 @@
+/* Copyright (C) 2002-2005 Jean-Marc Valin 
+   File: misc.c
+   Various utility routines for Speex
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "misc.h"
+
+#ifdef USER_MISC
+#include "user_misc.h"
+#endif
+
+#ifdef BFIN_ASM
+#include "misc_bfin.h"
+#endif
+
+#ifndef RELEASE
+void print_vec(float *vec, int len, char *name)
+{
+   int i;
+   printf ("%s ", name);
+   for (i=0;i<len;i++)
+      printf (" %f", vec[i]);
+   printf ("\n");
+}
+#endif
+
+#ifdef FIXED_DEBUG
+long long spx_mips=0;
+#endif
+
+
+spx_uint32_t be_int(spx_uint32_t i)
+{
+   spx_uint32_t ret=i;
+#ifndef WORDS_BIGENDIAN
+   ret =  i>>24;
+   ret += (i>>8)&0x0000ff00;
+   ret += (i<<8)&0x00ff0000;
+   ret += (i<<24);
+#endif
+   return ret;
+}
+
+spx_uint32_t le_int(spx_uint32_t i)
+{
+   spx_uint32_t ret=i;
+#ifdef WORDS_BIGENDIAN
+   ret =  i>>24;
+   ret += (i>>8)&0x0000ff00;
+   ret += (i<<8)&0x00ff0000;
+   ret += (i<<24);
+#endif
+   return ret;
+}
+
+#ifndef OVERRIDE_SPEEX_ALLOC
+void *speex_alloc (int size)
+{
+   return calloc(size,1);
+}
+#endif
+
+#ifndef OVERRIDE_SPEEX_ALLOC_SCRATCH
+void *speex_alloc_scratch (int size)
+{
+   return calloc(size,1);
+}
+#endif
+
+#ifndef OVERRIDE_SPEEX_REALLOC
+void *speex_realloc (void *ptr, int size)
+{
+   return realloc(ptr, size);
+}
+#endif
+
+#ifndef OVERRIDE_SPEEX_FREE
+void speex_free (void *ptr)
+{
+   free(ptr);
+}
+#endif
+
+#ifndef OVERRIDE_SPEEX_FREE_SCRATCH
+void speex_free_scratch (void *ptr)
+{
+   free(ptr);
+}
+#endif
+
+#ifndef OVERRIDE_SPEEX_MOVE
+void *speex_move (void *dest, void *src, int n)
+{
+   return memmove(dest,src,n);
+}
+#endif
+
+#ifndef OVERRIDE_SPEEX_ERROR
+void speex_error(const char *str)
+{
+   fprintf (stderr, "Fatal (internal) error: %s\n", str);
+   exit(1);
+}
+#endif
+
+#ifndef OVERRIDE_SPEEX_WARNING
+void speex_warning(const char *str)
+{
+#ifndef DISABLE_WARNINGS
+   fprintf (stderr, "warning: %s\n", str);
+#endif
+}
+#endif
+
+#ifndef OVERRIDE_SPEEX_WARNING_INT
+void speex_warning_int(const char *str, int val)
+{
+#ifndef DISABLE_WARNINGS
+   fprintf (stderr, "warning: %s %d\n", str, val);
+#endif
+}
+#endif
+
+#ifndef OVERRIDE_SPEEX_NOTIFY
+void speex_notify(const char *str)
+{
+#ifndef DISABLE_NOTIFICATIONS
+   fprintf (stderr, "notification: %s\n", str);
+#endif
+}
+#endif
+
+#ifdef FIXED_POINT
+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));
+}
+#else
+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
+
+#ifndef OVERRIDE_SPEEX_PUTC
+void _speex_putc(int ch, void *file)
+{
+   FILE *f = (FILE *)file;
+   fprintf(f, "%c", ch);
+}
+#endif
diff --git a/3rdparty/speex/libspeex/misc.h b/3rdparty/speex/libspeex/misc.h
new file mode 100644
index 0000000..25cf1c0
--- /dev/null
+++ b/3rdparty/speex/libspeex/misc.h
@@ -0,0 +1,119 @@
+/* Copyright (C) 2002 Jean-Marc Valin */
+/**
+   @file misc.h
+   @brief Various compatibility routines for Speex
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MISC_H
+#define MISC_H
+
+#ifndef SPEEX_VERSION
+#define SPEEX_MAJOR_VERSION 1         /**< Major Speex version. */
+#define SPEEX_MINOR_VERSION 1         /**< Minor Speex version. */
+#define SPEEX_MICRO_VERSION 13        /**< Micro Speex version. */
+#define SPEEX_EXTRA_VERSION ""        /**< Extra Speex version. */
+#define SPEEX_VERSION "speex-1.2beta1"  /**< Speex version string. */
+#endif
+
+/* A couple test to catch stupid option combinations */
+#ifdef FIXED_POINT
+
+#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
+
+#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
+
+#include "arch.h"
+
+#ifndef RELEASE
+/** Print a named vector to stdout */
+void print_vec(float *vec, int len, char *name);
+#endif
+
+/** Convert big endian */
+spx_uint32_t be_int(spx_uint32_t i);
+/** Convert little endian */
+spx_uint32_t le_int(spx_uint32_t i);
+
+/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_free */
+void *speex_alloc (int size);
+
+/** Same as speex_alloc, except that the area is only needed inside a Speex call (might cause problem with wideband though) */
+void *speex_alloc_scratch (int size);
+
+/** Speex wrapper for realloc. To do your own dynamic allocation, all you need to do is replace this function, speex_alloc and speex_free */
+void *speex_realloc (void *ptr, int size);
+
+/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_alloc */
+void speex_free (void *ptr);
+
+/** Same as speex_alloc, except that the area is only needed inside a Speex call (might cause problem with wideband though) */
+void speex_free_scratch (void *ptr);
+
+/** Speex wrapper for mem_move */
+void *speex_move (void *dest, void *src, int n);
+
+/** Abort with an error message to stderr (internal Speex error) */
+void speex_error(const char *str);
+
+/** Print warning message to stderr (programming error) */
+void speex_warning(const char *str);
+
+/** Print warning message with integer argument to stderr */
+void speex_warning_int(const char *str, int val);
+
+/** Print notification message to stderr */
+void speex_notify(const char *str);
+
+/** Generate a random number */
+spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed);
+
+/** Speex wrapper for putc */
+void _speex_putc(int ch, void *file);
+
+#endif
diff --git a/3rdparty/speex/libspeex/misc_bfin.h b/3rdparty/speex/libspeex/misc_bfin.h
new file mode 100644
index 0000000..77b082c
--- /dev/null
+++ b/3rdparty/speex/libspeex/misc_bfin.h
@@ -0,0 +1,54 @@
+/* Copyright (C) 2005 Analog Devices */
+/**
+   @file misc_bfin.h
+   @author Jean-Marc Valin 
+   @brief Various compatibility routines for Speex (Blackfin version)
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define OVERRIDE_SPEEX_MOVE
+void *speex_move (void *dest, void *src, int n)
+{
+   __asm__ __volatile__
+         (
+         "L0 = 0;\n\t"
+         "I0 = %0;\n\t"
+         "R0 = [I0++];\n\t"
+         "LOOP move%= LC0 = %2;\n\t"
+         "LOOP_BEGIN move%=;\n\t"
+            "[%1++] = R0 || R0 = [I0++];\n\t"
+         "LOOP_END move%=;\n\t"
+         "[%1++] = R0;\n\t"
+   : "=a" (src), "=a" (dest)
+   : "a" ((n>>2)-1), "0" (src), "1" (dest)
+   : "R0", "I0", "L0", "memory"
+         );
+   return dest;
+}
diff --git a/3rdparty/speex/libspeex/modes.c b/3rdparty/speex/libspeex/modes.c
new file mode 100644
index 0000000..4b21ad7
--- /dev/null
+++ b/3rdparty/speex/libspeex/modes.c
@@ -0,0 +1,668 @@
+/* Copyright (C) 2002-2006 Jean-Marc Valin 
+   File: modes.c
+
+   Describes the different modes of the codec
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#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 "misc.h"
+#include <math.h>
+
+#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)*/
+static const ltp_params ltp_params_nb = {
+   gain_cdbk_nb,
+   7,
+   7
+};
+
+/* Parameters for Long-Term Prediction (LTP)*/
+static const ltp_params ltp_params_vlbr = {
+   gain_cdbk_lbr,
+   5,
+   0
+};
+
+/* Parameters for Long-Term Prediction (LTP)*/
+static const ltp_params ltp_params_lbr = {
+   gain_cdbk_lbr,
+   5,
+   7
+};
+
+/* Parameters for Long-Term Prediction (LTP)*/
+static const ltp_params ltp_params_med = {
+   gain_cdbk_lbr,
+   5,
+   7
+};
+
+/* Split-VQ innovation parameters for very low bit-rate narrowband */
+static const split_cb_params split_cb_nb_vlbr = {
+   10,               /*subvect_size*/
+   4,               /*nb_subvect*/
+   exc_10_16_table, /*shape_cb*/
+   4,               /*shape_bits*/
+   0,
+};
+
+/* Split-VQ innovation parameters for very low bit-rate narrowband */
+static const split_cb_params split_cb_nb_ulbr = {
+   20,               /*subvect_size*/
+   2,               /*nb_subvect*/
+   exc_20_32_table, /*shape_cb*/
+   5,               /*shape_bits*/
+   0,
+};
+
+/* Split-VQ innovation parameters for low bit-rate narrowband */
+static const split_cb_params split_cb_nb_lbr = {
+   10,              /*subvect_size*/
+   4,               /*nb_subvect*/
+   exc_10_32_table, /*shape_cb*/
+   5,               /*shape_bits*/
+   0,
+};
+
+
+/* Split-VQ innovation parameters narrowband */
+static const split_cb_params split_cb_nb = {
+   5,               /*subvect_size*/
+   8,               /*nb_subvect*/
+   exc_5_64_table, /*shape_cb*/
+   6,               /*shape_bits*/
+   0,
+};
+
+/* Split-VQ innovation parameters narrowband */
+static const split_cb_params split_cb_nb_med = {
+   8,               /*subvect_size*/
+   5,               /*nb_subvect*/
+   exc_8_128_table, /*shape_cb*/
+   7,               /*shape_bits*/
+   0,
+};
+
+/* Split-VQ innovation for low-band wideband */
+static const split_cb_params split_cb_sb = {
+   5,               /*subvect_size*/
+   8,              /*nb_subvect*/
+   exc_5_256_table,    /*shape_cb*/
+   8,               /*shape_bits*/
+   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 = {
+   0,
+   1,
+   0,
+   0,
+   /* LSP quantization */
+   lsp_quant_lbr,
+   lsp_unquant_lbr,
+   /* No pitch quantization */
+   forced_pitch_quant,
+   forced_pitch_unquant,
+   NULL,
+   /* No innovation quantization (noise only) */
+   noise_codebook_quant,
+   noise_codebook_unquant,
+   NULL,
+   -1,
+   43
+};
+
+/* 3.95 kbps very low bit-rate mode */
+static const SpeexSubmode nb_submode8 = {
+   0,
+   1,
+   0,
+   0,
+   /*LSP quantization*/
+   lsp_quant_lbr,
+   lsp_unquant_lbr,
+   /*No pitch quantization*/
+   forced_pitch_quant,
+   forced_pitch_unquant,
+   NULL,
+   /*Innovation quantization*/
+   split_cb_search_shape_sign,
+   split_cb_shape_sign_unquant,
+   &split_cb_nb_ulbr,
+   QCONST16(.5,15),
+   79
+};
+
+/* 5.95 kbps very low bit-rate mode */
+static const SpeexSubmode nb_submode2 = {
+   0,
+   0,
+   0,
+   0,
+   /*LSP quantization*/
+   lsp_quant_lbr,
+   lsp_unquant_lbr,
+   /*No pitch quantization*/
+   pitch_search_3tap,
+   pitch_unquant_3tap,
+   &ltp_params_vlbr,
+   /*Innovation quantization*/
+   split_cb_search_shape_sign,
+   split_cb_shape_sign_unquant,
+   &split_cb_nb_vlbr,
+   QCONST16(.6,15),
+   119
+};
+
+/* 8 kbps low bit-rate mode */
+static const SpeexSubmode nb_submode3 = {
+   -1,
+   0,
+   1,
+   0,
+   /*LSP quantization*/
+   lsp_quant_lbr,
+   lsp_unquant_lbr,
+   /*Pitch quantization*/
+   pitch_search_3tap,
+   pitch_unquant_3tap,
+   &ltp_params_lbr,
+   /*Innovation quantization*/
+   split_cb_search_shape_sign,
+   split_cb_shape_sign_unquant,
+   &split_cb_nb_lbr,
+   QCONST16(.55,15),
+   160
+};
+
+/* 11 kbps medium bit-rate mode */
+static const SpeexSubmode nb_submode4 = {
+   -1,
+   0,
+   1,
+   0,
+   /*LSP quantization*/
+   lsp_quant_lbr,
+   lsp_unquant_lbr,
+   /*Pitch quantization*/
+   pitch_search_3tap,
+   pitch_unquant_3tap,
+   &ltp_params_med,
+   /*Innovation quantization*/
+   split_cb_search_shape_sign,
+   split_cb_shape_sign_unquant,
+   &split_cb_nb_med,
+   QCONST16(.45,15),
+   220
+};
+
+/* 15 kbps high bit-rate mode */
+static const SpeexSubmode nb_submode5 = {
+   -1,
+   0,
+   3,
+   0,
+   /*LSP quantization*/
+   lsp_quant_nb,
+   lsp_unquant_nb,
+   /*Pitch quantization*/
+   pitch_search_3tap,
+   pitch_unquant_3tap,
+   &ltp_params_nb,
+   /*Innovation quantization*/
+   split_cb_search_shape_sign,
+   split_cb_shape_sign_unquant,
+   &split_cb_nb,
+   QCONST16(.3,15),
+   300
+};
+
+/* 18.2 high bit-rate mode */
+static const SpeexSubmode nb_submode6 = {
+   -1,
+   0,
+   3,
+   0,
+   /*LSP quantization*/
+   lsp_quant_nb,
+   lsp_unquant_nb,
+   /*Pitch quantization*/
+   pitch_search_3tap,
+   pitch_unquant_3tap,
+   &ltp_params_nb,
+   /*Innovation quantization*/
+   split_cb_search_shape_sign,
+   split_cb_shape_sign_unquant,
+   &split_cb_sb,
+   QCONST16(.2,15),
+   364
+};
+
+/* 24.6 kbps high bit-rate mode */
+static const SpeexSubmode nb_submode7 = {
+   -1,
+   0,
+   3,
+   1,
+   /*LSP quantization*/
+   lsp_quant_nb,
+   lsp_unquant_nb,
+   /*Pitch quantization*/
+   pitch_search_3tap,
+   pitch_unquant_3tap,
+   &ltp_params_nb,
+   /*Innovation quantization*/
+   split_cb_search_shape_sign,
+   split_cb_shape_sign_unquant,
+   &split_cb_nb,
+   QCONST16(.1,15),
+   492
+};
+
+
+/* Default mode for narrowband */
+static const SpeexNBMode nb_mode = {
+   160,    /*frameSize*/
+   40,     /*subframeSize*/
+   10,     /*lpcSize*/
+   17,     /*pitchStart*/
+   144,    /*pitchEnd*/
+#ifdef FIXED_POINT
+   29491, 19661, /* gamma1, gamma2 */
+#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,
+   {1, 8, 2, 3, 3, 4, 4, 5, 5, 6, 7}
+};
+
+
+/* Default mode for narrowband */
+const SpeexMode speex_nb_mode = {
+   &nb_mode,
+   nb_mode_query,
+   "narrowband",
+   0,
+   4,
+   &nb_encoder_init,
+   &nb_encoder_destroy,
+   &nb_encode,
+   &nb_decoder_init,
+   &nb_decoder_destroy,
+   &nb_decode,
+   &nb_encoder_ctl,
+   &nb_decoder_ctl,
+};
+
+
+/* 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*/
+   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},
+   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*/
+   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},
+   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,
+   &ltp_params_48k,
+   /*Innovation quantization*/
+   split_cb_search_shape_sign,
+   split_cb_shape_sign_unquant,
+   &split_cb_nb_48k,
+   QCONST16(.7,15),
+   144
+};
+
+
+/* Special, non-standard 4.8 kbps mode */
+static const SpeexNBMode nb_48k_mode = {
+   240,    /*frameSize*/
+   48,     /*subframeSize*/
+   10,     /*lpcSize*/
+   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)
+{
+   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;
+#endif
+
+  if (mode < 0 || mode > SPEEX_NB_MODES) return NULL;
+
+  return speex_mode_list[mode];
+}
diff --git a/3rdparty/speex/libspeex/modes.h b/3rdparty/speex/libspeex/modes.h
new file mode 100644
index 0000000..5bf1971
--- /dev/null
+++ b/3rdparty/speex/libspeex/modes.h
@@ -0,0 +1,166 @@
+/* Copyright (C) 2002-2006 Jean-Marc Valin */
+/**
+   @file modes.h
+   @brief Describes the different modes of the codec
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef MODES_H
+#define MODES_H
+
+#include <speex/speex.h>
+#include <speex/speex_bits.h>
+#include "misc.h"
+
+#define NB_SUBMODES 16
+#define NB_SUBMODE_BITS 4
+
+#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 *);
+
+/** Decodes quantized LSPs */
+typedef void (*lsp_unquant_func)(spx_lsp_t *, int, SpeexBits *);
+
+
+/** Long-term predictor quantization */
+typedef int (*ltp_quant_func)(spx_word16_t *, spx_word16_t *, spx_coef_t *, spx_coef_t *, 
+                              spx_coef_t *, spx_sig_t *, const void *, int, int, spx_word16_t, 
+                              int, int, SpeexBits*, char *, spx_word16_t *, spx_word16_t *, int, int, int, spx_word32_t *);
+
+/** Long-term un-quantize */
+typedef void (*ltp_unquant_func)(spx_word16_t *, spx_word32_t *, int, int, spx_word16_t, const void *, int, int *,
+                                 spx_word16_t *, SpeexBits*, char*, int, int, spx_word16_t, int);
+
+
+/** Innovation quantization function */
+typedef void (*innovation_quant_func)(spx_word16_t *, spx_coef_t *, spx_coef_t *, spx_coef_t *, const void *, int, int, 
+                                      spx_sig_t *, spx_word16_t *, SpeexBits *, char *, int, int);
+
+/** Innovation unquantization function */
+typedef void (*innovation_unquant_func)(spx_sig_t *, const void *, int, SpeexBits*, char *, spx_int32_t *);
+
+/** Description of a Speex sub-mode (wither narrowband or wideband */
+typedef struct SpeexSubmode {
+   int     lbr_pitch;          /**< Set to -1 for "normal" modes, otherwise encode pitch using a global pitch and allowing a +- lbr_pitch variation (for low not-rates)*/
+   int     forced_pitch_gain;  /**< Use the same (forced) pitch gain for all sub-frames */
+   int     have_subframe_gain; /**< Number of bits to use as sub-frame innovation gain */
+   int     double_codebook;    /**< Apply innovation quantization twice for higher quality (and higher bit-rate)*/
+   /*LSP functions*/
+   lsp_quant_func    lsp_quant; /**< LSP quantization function */
+   lsp_unquant_func  lsp_unquant; /**< LSP unquantization function */
+
+   /*Lont-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) */
+
+   /*Quantization of innovation*/
+   innovation_quant_func innovation_quant; /**< Innovation quantization */
+   innovation_unquant_func innovation_unquant; /**< Innovation un-quantization */
+   const void             *innovation_params; /**< Innovation quantization parameters*/
+
+   spx_word16_t      comb_gain;  /**< Gain of enhancer comb filter */
+
+   int               bits_per_frame; /**< Number of bits per frame after encoding*/
+} SpeexSubmode;
+
+/** Struct defining the encoding/decoding mode*/
+typedef struct SpeexNBMode {
+   int     frameSize;      /**< Size of frames used for encoding */
+   int     subframeSize;   /**< Size of sub-frames used for encoding */
+   int     lpcSize;        /**< Order of LPC filter */
+   int     pitchStart;     /**< Smallest pitch value allowed */
+   int     pitchEnd;       /**< Largest pitch value allowed */
+
+   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 */
+} SpeexNBMode;
+
+
+/** Struct defining the encoding/decoding mode for SB-CELP (wideband) */
+typedef struct SpeexSBMode {
+   const SpeexMode *nb_mode;    /**< Embedded narrowband mode */
+   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 */
+   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 */
+   const float (*vbr_thresh)[11];
+   int     nb_modes;
+} SpeexSBMode;
+
+int speex_encode_native(void *state, spx_word16_t *in, SpeexBits *bits);
+int speex_decode_native(void *state, SpeexBits *bits, spx_word16_t *out);
+
+int nb_mode_query(const void *mode, int request, void *ptr);
+int wb_mode_query(const void *mode, int request, void *ptr);
+
+#endif
diff --git a/3rdparty/speex/libspeex/nb_celp.c b/3rdparty/speex/libspeex/nb_celp.c
new file mode 100644
index 0000000..1828aed
--- /dev/null
+++ b/3rdparty/speex/libspeex/nb_celp.c
@@ -0,0 +1,2049 @@
+/* Copyright (C) 2002-2006 Jean-Marc Valin 
+   File: nb_celp.c
+
+   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 <math.h>
+#include "nb_celp.h"
+#include "lpc.h"
+#include "lsp.h"
+#include "ltp.h"
+#include "quant_lsp.h"
+#include "cb_search.h"
+#include "filters.h"
+#include "stack_alloc.h"
+#include "vq.h"
+#include <speex/speex_bits.h>
+#include "vbr.h"
+#include "misc.h"
+#include "math_approx.h"
+#include <speex/speex_callbacks.h>
+
+#ifdef VORBIS_PSYCHO
+#include "vorbis_psy.h"
+#endif
+
+#ifndef M_PI
+#define M_PI           3.14159265358979323846  /* pi */
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define SUBMODE(x) st->submodes[st->submodeID]->x
+
+/* Default size for the encoder and decoder stack (can be changed at compile time).
+   This does not apply when using variable-size arrays or alloca. */
+#ifndef NB_ENC_STACK
+#define NB_ENC_STACK (8000*sizeof(spx_sig_t))
+#endif
+
+#ifndef NB_DEC_STACK
+#define NB_DEC_STACK (4000*sizeof(spx_sig_t))
+#endif
+
+
+#ifdef FIXED_POINT
+const spx_word32_t ol_gain_table[32]={18900, 25150, 33468, 44536, 59265, 78865, 104946, 139653, 185838, 247297, 329081, 437913, 582736, 775454, 1031906, 1373169, 1827293, 2431601, 3235761, 4305867, 5729870, 7624808, 10146425, 13501971, 17967238, 23909222, 31816294, 42338330, 56340132, 74972501, 99766822, 132760927};
+const spx_word16_t exc_gain_quant_scal3_bound[7]={1841, 3883, 6051, 8062, 10444, 13580, 18560};
+const spx_word16_t exc_gain_quant_scal3[8]={1002, 2680, 5086, 7016, 9108, 11781, 15380, 21740};
+const spx_word16_t exc_gain_quant_scal1_bound[1]={14385};
+const spx_word16_t exc_gain_quant_scal1[2]={11546, 17224};
+
+#define LSP_MARGIN 16
+#define LSP_DELTA1 6553
+#define LSP_DELTA2 1638
+
+#else
+
+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 .002f
+#define LSP_DELTA1 .2f
+#define LSP_DELTA2 .05f
+
+#endif
+
+#ifdef VORBIS_PSYCHO
+#define EXTRA_BUFFER 100
+#else
+#define EXTRA_BUFFER 0
+#endif
+
+
+#define sqr(x) ((x)*(x))
+
+extern const spx_word16_t lpc_window[];
+
+void *nb_encoder_init(const SpeexMode *m)
+{
+   EncState *st;
+   const SpeexNBMode *mode;
+   int i;
+
+   mode=(const SpeexNBMode *)m->mode;
+   st = (EncState*)speex_alloc(sizeof(EncState));
+   if (!st)
+      return NULL;
+#if defined(VAR_ARRAYS) || defined (USE_ALLOCA)
+   st->stack = NULL;
+#else
+   st->stack = (char*)speex_alloc_scratch(NB_ENC_STACK);
+#endif
+   
+   st->mode=m;
+
+   st->frameSize = mode->frameSize;
+   st->nbSubframes=mode->frameSize/mode->subframeSize;
+   st->subframeSize=mode->subframeSize;
+   st->windowSize = st->frameSize+st->subframeSize;
+   st->lpcSize = mode->lpcSize;
+   st->gamma1=mode->gamma1;
+   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;
+   st->submodeID=st->submodeSelect=mode->defaultSubmode;
+   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);
+   st->curve = (float*)speex_alloc(128*sizeof(float));
+   st->old_curve = (float*)speex_alloc(128*sizeof(float));
+   st->psy_window = (float*)speex_alloc(256*sizeof(float));
+#endif
+
+   st->cumul_gain = 1024;
+
+   /* Allocating input buffer */
+   st->winBuf = (spx_word16_t*)speex_alloc((st->windowSize-st->frameSize)*sizeof(spx_word16_t));
+   /* Allocating excitation buffer */
+   st->excBuf = (spx_word16_t*)speex_alloc((mode->frameSize+mode->pitchEnd+2)*sizeof(spx_word16_t));
+   st->exc = st->excBuf + mode->pitchEnd + 2;
+   st->swBuf = (spx_word16_t*)speex_alloc((mode->frameSize+mode->pitchEnd+2)*sizeof(spx_word16_t));
+   st->sw = st->swBuf + mode->pitchEnd + 2;
+
+   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;i<st->lpcSize+1;i++)
+      st->lagWindow[i]=16384*exp(-.5*sqr(2*M_PI*st->lag_factor*i));
+
+   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;i<st->lpcSize;i++)
+   {
+      st->old_lsp[i]=LSP_SCALING*(M_PI*((float)(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));
+   st->mem_sw_whole = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t));
+   st->mem_exc = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t));
+   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_rms_save = NULL;
+   
+   st->pitch = (int*)speex_alloc((st->nbSubframes)*sizeof(int));
+
+   st->vbr = (VBRState*)speex_alloc(sizeof(VBRState));
+   vbr_init(st->vbr);
+   st->vbr_quality = 8;
+   st->vbr_enabled = 0;
+   st->vbr_max = 0;
+   st->vad_enabled = 0;
+   st->dtx_enabled = 0;
+   st->abr_enabled = 0;
+   st->abr_drift = 0;
+
+   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));
+#endif
+   return st;
+}
+
+void nb_encoder_destroy(void *state)
+{
+   EncState *st=(EncState *)state;
+   /* Free all allocated memory */
+#if !(defined(VAR_ARRAYS) || defined (USE_ALLOCA))
+   speex_free_scratch(st->stack);
+#endif
+
+   speex_free (st->winBuf);
+   speex_free (st->excBuf);
+   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);
+   speex_free (st->mem_sw_whole);
+   speex_free (st->mem_exc);
+   speex_free (st->mem_exc2);
+   speex_free (st->pi_gain);
+   speex_free (st->pitch);
+
+   vbr_destroy(st->vbr);
+   speex_free (st->vbr);
+
+#ifdef VORBIS_PSYCHO
+   vorbis_psy_destroy(st->psy);
+   speex_free (st->curve);
+   speex_free (st->old_curve);
+   speex_free (st->psy_window);
+#endif
+
+   /*Free state memory... should be last*/
+   speex_free(st);
+}
+
+int nb_encode(void *state, void *vin, SpeexBits *bits)
+{
+   EncState *st;
+   int i, sub, roots;
+   int ol_pitch;
+   spx_word16_t ol_pitch_coef;
+   spx_word32_t ol_gain;
+   VARDECL(spx_word16_t *ringing);
+   VARDECL(spx_word16_t *target);
+   VARDECL(spx_sig_t *innov);
+   VARDECL(spx_word32_t *exc32);
+   VARDECL(spx_mem_t *mem);
+   VARDECL(spx_coef_t *bw_lpc1);
+   VARDECL(spx_coef_t *bw_lpc2);
+   VARDECL(spx_coef_t *lpc);
+   VARDECL(spx_lsp_t *lsp);
+   VARDECL(spx_lsp_t *qlsp);
+   VARDECL(spx_lsp_t *interp_lsp);
+   VARDECL(spx_lsp_t *interp_qlsp);
+   VARDECL(spx_coef_t *interp_lpc);
+   VARDECL(spx_coef_t *interp_qlpc);
+   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;
+   stack=st->stack;
+
+   ALLOC(lpc, st->lpcSize, spx_coef_t);
+   ALLOC(bw_lpc1, st->lpcSize, spx_coef_t);
+   ALLOC(bw_lpc2, st->lpcSize, spx_coef_t);
+   ALLOC(lsp, st->lpcSize, spx_lsp_t);
+   ALLOC(qlsp, st->lpcSize, spx_lsp_t);
+   ALLOC(interp_lsp, st->lpcSize, spx_lsp_t);
+   ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t);
+   ALLOC(interp_lpc, st->lpcSize, spx_coef_t);
+   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));
+
+   if (st->highpass_enabled)
+      highpass(in, in, st->frameSize, (st->isWideband?HIGHPASS_WIDEBAND:HIGHPASS_NARROWBAND)|HIGHPASS_INPUT, st->mem_hp);
+   
+   {
+      VARDECL(spx_word16_t *w_sig);
+      VARDECL(spx_word16_t *autocorr);
+      ALLOC(w_sig, st->windowSize, spx_word16_t);
+      ALLOC(autocorr, st->lpcSize+1, spx_word16_t);
+      /* Window for analysis */
+      for (i=0;i<st->windowSize-st->frameSize;i++)
+         w_sig[i] = EXTRACT16(SHR32(MULT16_16(st->winBuf[i],st->window[i]),SIG_SHIFT));
+      for (;i<st->windowSize;i++)
+         w_sig[i] = EXTRACT16(SHR32(MULT16_16(in[i-st->windowSize+st->frameSize],st->window[i]),SIG_SHIFT));
+      /* Compute auto-correlation */
+      _spx_autocorr(w_sig, autocorr, st->lpcSize+1, st->windowSize);
+      autocorr[0] = ADD16(autocorr[0],MULT16_16_Q15(autocorr[0],st->lpc_floor)); /* Noise floor in auto-correlation domain */
+
+      /* Lag windowing: equivalent to filtering in the power-spectrum domain */
+      for (i=0;i<st->lpcSize+1;i++)
+         autocorr[i] = MULT16_16_Q14(autocorr[i],st->lagWindow[i]);
+
+      /* Levinson-Durbin */
+      _spx_lpc(lpc, autocorr, st->lpcSize);
+      /* LPC to LSPs (x-domain) transform */
+      roots=lpc_to_lsp (lpc, st->lpcSize, lsp, 10, LSP_DELTA1, stack);
+      /* Check if we found all the roots */
+      if (roots!=st->lpcSize)
+      {
+         /*If we can't find all LSP's, do some damage control and use previous filter*/
+         for (i=0;i<st->lpcSize;i++)
+         {
+            lsp[i]=st->old_lsp[i];
+         }
+      }
+   }
+
+
+
+
+   /* Whole frame analysis (open-loop estimation of pitch and excitation gain) */
+   {
+      if (st->first)
+         for (i=0;i<st->lpcSize;i++)
+            interp_lsp[i] = lsp[i];
+      else
+         lsp_interpolate(st->old_lsp, lsp, interp_lsp, st->lpcSize, st->nbSubframes, st->nbSubframes<<1);
+
+      lsp_enforce_margin(interp_lsp, st->lpcSize, LSP_MARGIN);
+
+      /* Compute interpolated LPCs (unquantized) for whole frame*/
+      lsp_to_lpc(interp_lsp, interp_lpc, st->lpcSize,stack);
+
+
+      /*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)
+      {
+         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;i<st->windowSize-st->frameSize;i++)
+            st->sw[i] = st->winBuf[i];
+         for (;i<st->frameSize;i++)
+            st->sw[i] = in[i-st->windowSize+st->frameSize];
+         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, 
+                               nol_pitch, nol_pitch_coef, 6, stack);
+         ol_pitch=nol_pitch[0];
+         ol_pitch_coef = nol_pitch_coef[0];
+         /*Try to remove pitch multiples*/
+         for (i=1;i<6;i++)
+         {
+#ifdef FIXED_POINT
+            if ((nol_pitch_coef[i]>MULT16_16_Q15(nol_pitch_coef[0],27853)) && 
+#else
+            if ((nol_pitch_coef[i]>.85*nol_pitch_coef[0]) && 
+#endif
+                (ABS(2*nol_pitch[i]-ol_pitch)<=2 || ABS(3*nol_pitch[i]-ol_pitch)<=3 || 
+                 ABS(4*nol_pitch[i]-ol_pitch)<=4 || ABS(5*nol_pitch[i]-ol_pitch)<=5))
+            {
+               /*ol_pitch_coef=nol_pitch_coef[i];*/
+               ol_pitch = nol_pitch[i];
+            }
+         }
+         /*if (ol_pitch>50)
+           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;i<st->windowSize-st->frameSize;i++)
+         st->exc[i] = st->winBuf[i];
+      for (;i<st->frameSize;i++)
+         st->exc[i] = in[i-st->windowSize+st->frameSize];
+      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=SHR32(sqrt(1+ol_gain2/st->frameSize),SIG_SHIFT);
+
+      } else
+#endif
+      {
+         spx_word16_t g = compute_rms16(st->exc, st->frameSize);
+         if (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
+            ol_gain = SHL32(EXTEND32(g),SIG_SHIFT);
+      }
+   }
+
+#ifdef VORBIS_PSYCHO
+   for(i=0;i<256-st->frameSize;i++)
+      st->psy_window[i] = st->psy_window[i+st->frameSize];
+   for(i=0;i<st->frameSize;i++)
+      st->psy_window[256-st->frameSize+i] = in[i];
+   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];
+#endif
+
+   /*VBR stuff*/
+   if (st->vbr && (st->vbr_enabled||st->vad_enabled))
+   {
+      float lsp_dist=0;
+      for (i=0;i<st->lpcSize;i++)
+         lsp_dist += (st->old_lsp[i] - lsp[i])*(st->old_lsp[i] - lsp[i]);
+      lsp_dist /= LSP_SCALING*LSP_SCALING;
+      
+      if (st->abr_enabled)
+      {
+         float qual_change=0;
+         if (st->abr_drift2 * st->abr_drift > 0)
+         {
+            /* Only adapt if long-term and short-term drift are the same sign */
+            qual_change = -.00001*st->abr_drift/(1+st->abr_count);
+            if (qual_change>.05)
+               qual_change=.05;
+            if (qual_change<-.05)
+               qual_change=-.05;
+         }
+         st->vbr_quality += qual_change;
+         if (st->vbr_quality>10)
+            st->vbr_quality=10;
+         if (st->vbr_quality<0)
+            st->vbr_quality=0;
+      }
+
+      st->relative_quality = vbr_analysis(st->vbr, in, st->frameSize, ol_pitch, GAIN_SCALING_1*ol_pitch_coef);
+      /*if (delta_qual<0)*/
+      /*  delta_qual*=.1*(3+st->vbr_quality);*/
+      if (st->vbr_enabled) 
+      {
+         spx_int32_t mode;
+         int choice=0;
+         float min_diff=100;
+         mode = 8;
+         while (mode)
+         {
+            int v1;
+            float thresh;
+            v1=(int)floor(st->vbr_quality);
+            if (v1==10)
+               thresh = vbr_nb_thresh[mode][v1];
+            else
+               thresh = (st->vbr_quality-v1)*vbr_nb_thresh[mode][v1+1] + (1+v1-st->vbr_quality)*vbr_nb_thresh[mode][v1];
+            if (st->relative_quality > thresh && 
+                st->relative_quality-thresh<min_diff)
+            {
+               choice = mode;
+               min_diff = st->relative_quality-thresh;
+            }
+            mode--;
+         }
+         mode=choice;
+         if (mode==0)
+         {
+            if (st->dtx_count==0 || lsp_dist>.05 || !st->dtx_enabled || st->dtx_count>20)
+            {
+               mode=1;
+               st->dtx_count=1;
+            } else {
+               mode=0;
+               st->dtx_count++;
+            }
+         } else {
+            st->dtx_count=0;
+         }
+
+         speex_encoder_ctl(state, SPEEX_SET_MODE, &mode);
+         if (st->vbr_max>0)
+         {
+            spx_int32_t rate;
+            speex_encoder_ctl(state, SPEEX_GET_BITRATE, &rate);
+            if (rate > st->vbr_max)
+            {
+               rate = st->vbr_max;
+               speex_encoder_ctl(state, SPEEX_SET_BITRATE, &rate);
+            }
+         }
+         
+         if (st->abr_enabled)
+         {
+            spx_int32_t bitrate;
+            speex_encoder_ctl(state, SPEEX_GET_BITRATE, &bitrate);
+            st->abr_drift+=(bitrate-st->abr_enabled);
+            st->abr_drift2 = .95*st->abr_drift2 + .05*(bitrate-st->abr_enabled);
+            st->abr_count += 1.0;
+         }
+
+      } else {
+         /*VAD only case*/
+         int mode;
+         if (st->relative_quality<2)
+         {
+            if (st->dtx_count==0 || lsp_dist>.05 || !st->dtx_enabled || st->dtx_count>20)
+            {
+               st->dtx_count=1;
+               mode=1;
+            } else {
+               mode=0;
+               st->dtx_count++;
+            }
+         } else {
+            st->dtx_count = 0;
+            mode=st->submodeSelect;
+         }
+         /*speex_encoder_ctl(state, SPEEX_SET_MODE, &mode);*/
+         st->submodeID=mode;
+      } 
+   } else {
+      st->relative_quality = -1;
+   }
+
+   if (st->encode_submode)
+   {
+#ifdef EPIC_48K
+   if (!st->lbr_48k) {
+#endif
+
+   /* 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);
+
+#ifdef EPIC_48K
+   }
+#endif
+   }
+
+   /* If null mode (no transmission), just set a couple things to zero*/
+   if (st->submodes[st->submodeID] == NULL)
+   {
+      for (i=0;i<st->frameSize;i++)
+         st->exc[i]=st->sw[i]=VERY_SMALL;
+
+      for (i=0;i<st->lpcSize;i++)
+         st->mem_sw[i]=0;
+      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));
+
+      /* Clear memory (no need to really compute it) */
+      for (i=0;i<st->lpcSize;i++)
+         st->mem_sp[i] = 0;
+      return 0;
+
+   }
+
+   /* LSP Quantization */
+   if (st->first)
+   {
+      for (i=0;i<st->lpcSize;i++)
+         st->old_lsp[i] = lsp[i];
+   }
+
+
+   /*Quantize LSPs*/
+#if 1 /*0 for unquantized*/
+   SUBMODE(lsp_quant)(lsp, qlsp, st->lpcSize, bits);
+#else
+   for (i=0;i<st->lpcSize;i++)
+     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)
+   {
+      speex_bits_pack(bits, ol_pitch-st->min_pitch, 7);
+   } 
+
+   if (SUBMODE(forced_pitch_gain))
+   {
+      int quant;
+      quant = (int)floor(.5+15*ol_pitch_coef*GAIN_SCALING_1);
+      if (quant>15)
+         quant=15;
+      if (quant<0)
+         quant=0;
+      speex_bits_pack(bits, quant, 4);
+      ol_pitch_coef=GAIN_SCALING*0.066667*quant;
+   }
+   
+   
+   /*Quantize and transmit open-loop excitation gain*/
+#ifdef FIXED_POINT
+   {
+      int qe = scal_quant32(ol_gain, ol_gain_table, 32);
+      /*ol_gain = exp(qe/3.5)*SIG_SCALING;*/
+      ol_gain = MULT16_32_Q15(28406,ol_gain_table[qe]);
+      speex_bits_pack(bits, qe, 5);
+   }
+#else
+   {
+      int qe = (int)(floor(.5+3.5*log(ol_gain*1.0/SIG_SCALING)));
+      if (qe<0)
+         qe=0;
+      if (qe>31)
+         qe=31;
+      ol_gain = exp(qe/3.5)*SIG_SCALING;
+      speex_bits_pack(bits, qe, 5);
+   }
+#endif
+
+
+#ifdef EPIC_48K
+   }
+#endif
+
+
+   /* Special case for first frame */
+   if (st->first)
+   {
+      for (i=0;i<st->lpcSize;i++)
+         st->old_qlsp[i] = qlsp[i];
+   }
+
+   /* Target signal */
+   ALLOC(target, st->subframeSize, spx_word16_t);
+   ALLOC(innov, st->subframeSize, spx_sig_t);
+   ALLOC(exc32, st->subframeSize, spx_word32_t);
+   ALLOC(ringing, st->subframeSize, spx_word16_t);
+   ALLOC(syn_resp, st->subframeSize, spx_word16_t);
+   ALLOC(real_exc, st->subframeSize, spx_word16_t);
+   ALLOC(mem, st->lpcSize, spx_mem_t);
+
+   /* Loop on sub-frames */
+   for (sub=0;sub<st->nbSubframes;sub++)
+   {
+      int   offset;
+      spx_word16_t *sw;
+      spx_word16_t *exc;
+      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;
+      /* Excitation */
+      exc=st->exc+offset;
+      /* Weighted signal */
+      sw=st->sw+offset;
+      
+      /* LSP interpolation (quantized and unquantized) */
+      lsp_interpolate(st->old_lsp, lsp, interp_lsp, st->lpcSize, sub, st->nbSubframes);
+      lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpcSize, sub, st->nbSubframes);
+
+      /* Make sure the filters are stable */
+      lsp_enforce_margin(interp_lsp, st->lpcSize, LSP_MARGIN);
+      lsp_enforce_margin(interp_qlsp, st->lpcSize, LSP_MARGIN);
+
+      /* Compute interpolated LPCs (quantized and unquantized) */
+      lsp_to_lpc(interp_lsp, interp_lpc, st->lpcSize,stack);
+
+      lsp_to_lpc(interp_qlsp, interp_qlpc, st->lpcSize, stack);
+
+      /* Compute analysis filter gain at w=pi (for use in SB-CELP) */
+      {
+         spx_word32_t pi_g=LPC_SCALING;
+         for (i=0;i<st->lpcSize;i+=2)
+         {
+            /*pi_g += -st->interp_qlpc[i] +  st->interp_qlpc[i+1];*/
+            pi_g = ADD32(pi_g, SUB32(EXTEND32(interp_qlpc[i+1]),EXTEND32(interp_qlpc[i])));
+         }
+         st->pi_gain[sub] = pi_g;
+      }
+
+#ifdef VORBIS_PSYCHO
+      {
+         float curr_curve[128];
+         float fact = ((float)sub+1.0f)/st->nbSubframes;
+         for (i=0;i<128;i++)
+            curr_curve[i] = (1.0f-fact)*st->old_curve[i] + fact*st->curve[i];
+         curve_to_lpc(st->psy, curr_curve, bw_lpc1, bw_lpc2, 10);
+      }
+#else
+      /* Compute bandwidth-expanded (unquantized) LPCs for perceptual weighting */
+      bw_lpc(st->gamma1, interp_lpc, bw_lpc1, st->lpcSize);
+      if (st->gamma2>=0)
+         bw_lpc(st->gamma2, interp_lpc, bw_lpc2, st->lpcSize);
+      else
+      {
+         bw_lpc2[0]=1;
+         for (i=1;i<=st->lpcSize;i++)
+            bw_lpc2[i]=0;
+      }
+      /*print_vec(st->bw_lpc1, 10, "bw_lpc");*/
+#endif
+
+      {
+         /*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;i<st->subframeSize;i++)
+               real_exc[i] = sw[i] = st->winBuf[i];
+         } else {
+            for (i=0;i<st->subframeSize;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);
+      
+      if (st->complexity==0)
+         response_bound >>= 1;
+      compute_impulse_response(interp_qlpc, bw_lpc1, bw_lpc2, syn_resp, response_bound, st->lpcSize, stack);
+      for (i=response_bound;i<st->subframeSize;i++)
+         syn_resp[i]=VERY_SMALL;
+      
+      /* Compute zero response of A(z/g1) / ( A(z/g2) * A(z) ) */
+      for (i=0;i<st->lpcSize;i++)
+         mem[i]=SHL32(st->mem_sp[i],1);
+      for (i=0;i<st->subframeSize;i++)
+         ringing[i] = VERY_SMALL;
+#ifdef SHORTCUTS2
+      iir_mem16(ringing, interp_qlpc, ringing, response_bound, st->lpcSize, mem, stack);
+      for (i=0;i<st->lpcSize;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;i<st->subframeSize;i++)
+         ringing[i]=0;
+#else
+      iir_mem16(ringing, interp_qlpc, ringing, st->subframeSize, st->lpcSize, mem, stack);
+      for (i=0;i<st->lpcSize;i++)
+         mem[i]=SHL32(st->mem_sw[i],1);
+      filter_mem16(ringing, bw_lpc1, bw_lpc2, ringing, st->subframeSize, st->lpcSize, mem, stack);
+#endif
+      
+      /* Compute weighted signal */
+      for (i=0;i<st->lpcSize;i++)
+         mem[i]=st->mem_sw[i];
+      filter_mem16(sw, bw_lpc1, bw_lpc2, sw, st->subframeSize, st->lpcSize, mem, stack);
+      
+      if (st->complexity==0)
+         for (i=0;i<st->lpcSize;i++)
+            st->mem_sw[i]=mem[i];
+      
+      /* Compute target signal (saturation prevents overflows on clipped input speech) */
+      for (i=0;i<st->subframeSize;i++)
+         target[i]=EXTRACT16(SATURATE(SUB32(sw[i],PSHR32(ringing[i],1)),32767));
+
+      /* Reset excitation */
+      for (i=0;i<st->subframeSize;i++)
+         exc[i]=0;
+
+      /* If we have a long-term predictor (otherwise, something's wrong) */
+      if (SUBMODE(ltp_quant))
+      {
+         int pit_min, pit_max;
+         /* Long-term prediction */
+         if (SUBMODE(lbr_pitch) != -1)
+         {
+            /* Low bit-rate pitch handling */
+            int margin;
+            margin = SUBMODE(lbr_pitch);
+            if (margin)
+            {
+               if (ol_pitch < st->min_pitch+margin-1)
+                  ol_pitch=st->min_pitch+margin-1;
+               if (ol_pitch > st->max_pitch-margin)
+                  ol_pitch=st->max_pitch-margin;
+               pit_min = ol_pitch-margin+1;
+               pit_max = ol_pitch+margin;
+            } else {
+               pit_min=pit_max=ol_pitch;
+            }
+         } else {
+            pit_min = st->min_pitch;
+            pit_max = st->max_pitch;
+         }
+         
+         /* Force pitch to use only the current frame if needed */
+         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 */
+      for (i=0;i<st->subframeSize;i++)
+         innov[i]=0;
+      
+      /* FIXME: Make sure this is save from overflows (so far so good) */
+      for (i=0;i<st->subframeSize;i++)
+         real_exc[i] = EXTRACT16(SUB32(EXTEND32(real_exc[i]), PSHR32(exc32[i],SIG_SHIFT-1)));
+      
+      ener = SHL32(EXTEND32(compute_rms16(real_exc, st->subframeSize)),SIG_SHIFT);
+      
+      /*FIXME: Should use DIV32_16 and make sure result fits in 16 bits */
+#ifdef FIXED_POINT
+      {
+         spx_word32_t f = PDIV32(ener,PSHR32(ol_gain,SIG_SHIFT));
+         if (f<=32767)
+            fine_gain = f;
+         else
+            fine_gain = 32767;
+      }
+#else
+      fine_gain = PDIV32_16(ener,PSHR32(ol_gain,SIG_SHIFT));
+#endif
+      /* Calculate gain correction for the sub-frame (if any) */
+      if (SUBMODE(have_subframe_gain)) 
+      {
+         int qe;
+         if (SUBMODE(have_subframe_gain)==3)
+         {
+            qe = scal_quant(fine_gain, exc_gain_quant_scal3_bound, 8);
+            speex_bits_pack(bits, qe, 3);
+            ener=MULT16_32_Q14(exc_gain_quant_scal3[qe],ol_gain);
+         } else {
+            qe = scal_quant(fine_gain, exc_gain_quant_scal1_bound, 2);
+            speex_bits_pack(bits, qe, 1);
+            ener=MULT16_32_Q14(exc_gain_quant_scal1[qe],ol_gain);               
+         }
+      } else {
+         ener=ol_gain;
+      }
+      
+      /*printf ("%f %f\n", ener, ol_gain);*/
+      
+      /* Normalize innovation */
+      signal_div(target, target, ener, st->subframeSize);
+      
+      /* Quantize innovation */
+      if (SUBMODE(innovation_quant))
+      {
+         /* Codebook search */
+         SUBMODE(innovation_quant)(target, interp_qlpc, bw_lpc1, bw_lpc2, 
+                  SUBMODE(innovation_params), st->lpcSize, st->subframeSize, 
+                  innov, syn_resp, bits, stack, st->complexity, SUBMODE(double_codebook));
+         
+         /* De-normalize innovation and update excitation */
+         signal_mul(innov, innov, ener, st->subframeSize);
+         
+         for (i=0;i<st->subframeSize;i++)
+            exc[i] = EXTRACT16(SATURATE32(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT),32767));
+
+         /* 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);
+            for (i=0;i<st->subframeSize;i++)
+               innov2[i]=0;
+            for (i=0;i<st->subframeSize;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.454545f,15),ener), st->subframeSize);
+            for (i=0;i<st->subframeSize;i++)
+               innov[i] = ADD32(innov[i],innov2[i]);
+            stack = tmp_stack;
+         }
+         for (i=0;i<st->subframeSize;i++)
+            exc[i] = EXTRACT16(SATURATE32(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT),32767));
+         if (st->innov_rms_save)
+         {
+            st->innov_rms_save[sub] = compute_rms(innov, st->subframeSize);
+         }
+      } else {
+         speex_error("No fixed codebook");
+      }
+
+
+      for (i=0;i<st->subframeSize;i++)
+         sw[i] = exc[i];
+      /* Final signal synthesis from excitation */
+      iir_mem16(sw, 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)
+         filter_mem16(sw, bw_lpc1, bw_lpc2, sw, st->subframeSize, st->lpcSize, st->mem_sw, stack);
+      
+   }
+
+   /* Store the LSPs for interpolation in the next frame */
+   if (st->submodeID>=1)
+   {
+      for (i=0;i<st->lpcSize;i++)
+         st->old_lsp[i] = lsp[i];
+      for (i=0;i<st->lpcSize;i++)
+         st->old_qlsp[i] = qlsp[i];
+   }
+
+#ifdef VORBIS_PSYCHO
+   if (st->submodeID>=1)
+   {
+      for (i=0;i<128;i++)
+         st->old_curve[i] = st->curve[i];
+   }
+#endif
+
+   if (st->submodeID==1)
+   {
+      if (st->dtx_count)
+         speex_bits_pack(bits, 15, 4);
+      else
+         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));
+
+   if (SUBMODE(innovation_quant) == noise_codebook_quant || st->submodeID==0)
+      st->bounded_pitch = 1;
+   else
+      st->bounded_pitch = 0;
+
+   return 1;
+}
+
+void *nb_decoder_init(const SpeexMode *m)
+{
+   DecState *st;
+   const SpeexNBMode *mode;
+   int i;
+
+   mode=(const SpeexNBMode*)m->mode;
+   st = (DecState *)speex_alloc(sizeof(DecState));
+   if (!st)
+      return NULL;
+#if defined(VAR_ARRAYS) || defined (USE_ALLOCA)
+   st->stack = NULL;
+#else
+   st->stack = (char*)speex_alloc_scratch(NB_DEC_STACK);
+#endif
+
+   st->mode=m;
+
+
+   st->encode_submode = 1;
+#ifdef EPIC_48K
+   st->lbr_48k=mode->lbr48k;
+#endif
+
+   st->first=1;
+   /* Codec parameters, should eventually have several "modes"*/
+   st->frameSize = mode->frameSize;
+   st->nbSubframes=mode->frameSize/mode->subframeSize;
+   st->subframeSize=mode->subframeSize;
+   st->lpcSize = mode->lpcSize;
+   st->min_pitch=mode->pitchStart;
+   st->max_pitch=mode->pitchEnd;
+
+   st->submodes=mode->submodes;
+   st->submodeID=mode->defaultSubmode;
+
+   st->lpc_enh_enabled=1;
+
+   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;i<st->frameSize + st->max_pitch + 1;i++)
+      st->excBuf[i]=0;
+
+   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));
+   st->mem_sp = (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->last_pitch = 40;
+   st->count_lost=0;
+   st->pitch_gain_buf[0] = st->pitch_gain_buf[1] = st->pitch_gain_buf[2] = 0;
+   st->pitch_gain_buf_idx = 0;
+   st->seed = 1000;
+   
+   st->sampling_rate=8000;
+   st->last_ol_gain = 0;
+
+   st->user_callback.func = &speex_default_user_handler;
+   st->user_callback.data = NULL;
+   for (i=0;i<16;i++)
+      st->speex_callbacks[i].func = NULL;
+
+   st->voc_m1=st->voc_m2=st->voc_mean=0;
+   st->voc_offset=0;
+   st->dtx_enabled=0;
+   st->isWideband = 0;
+   st->highpass_enabled = 1;
+
+#ifdef ENABLE_VALGRIND
+   VALGRIND_MAKE_READABLE(st, (st->stack-(char*)st));
+#endif
+   return st;
+}
+
+void nb_decoder_destroy(void *state)
+{
+   DecState *st;
+   st=(DecState*)state;
+   
+#if !(defined(VAR_ARRAYS) || defined (USE_ALLOCA))
+   speex_free_scratch(st->stack);
+#endif
+
+   speex_free (st->excBuf);
+   speex_free (st->interp_qlpc);
+   speex_free (st->old_qlsp);
+   speex_free (st->mem_sp);
+   speex_free (st->pi_gain);
+
+   speex_free(state);
+}
+
+#define median3(a, b, c)	((a) < (b) ? ((b) < (c) ? (b) : ((a) < (c) ? (c) : (a))) : ((c) < (b) ? (b) : ((c) < (a) ? (c) : (a))))
+
+#ifdef FIXED_POINT
+const spx_word16_t attenuation[10] = {32767, 31483, 27923, 22861, 17278, 12055, 7764, 4616, 2533, 1283};
+#else
+const spx_word16_t attenuation[10] = {1., 0.961, 0.852, 0.698, 0.527, 0.368, 0.237, 0.141, 0.077, 0.039};
+
+#endif
+
+static void nb_decode_lost(DecState *st, spx_word16_t *out, char *stack)
+{
+   int i;
+   int pitch_val;
+   spx_word16_t pitch_gain;
+   spx_word16_t fact;
+   spx_word16_t gain_med;
+   spx_word16_t innov_gain;
+   spx_word16_t noise_gain;
+   
+   if (st->count_lost<10)
+      fact = attenuation[st->count_lost];
+   else
+      fact = 0;
+
+   gain_med = median3(st->pitch_gain_buf[0], st->pitch_gain_buf[1], st->pitch_gain_buf[2]);
+   if (gain_med < st->last_pitch_gain)
+      st->last_pitch_gain = gain_med;
+   
+#ifdef FIXED_POINT
+   pitch_gain = st->last_pitch_gain;
+   if (pitch_gain>54)
+      pitch_gain = 54;
+   pitch_gain = SHL16(pitch_gain, 9);
+#else   
+   pitch_gain = GAIN_SCALING_1*st->last_pitch_gain;
+   if (pitch_gain>.85)
+      pitch_gain=.85;
+#endif
+   pitch_gain = MULT16_16_Q15(fact,pitch_gain) + VERY_SMALL;
+   /* FIXME: This was rms of innovation (not exc) */
+   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));
+   
+
+   pitch_val = st->last_pitch + SHR32((spx_int32_t)speex_rand(1+st->count_lost, &st->seed),SIG_SHIFT);
+   if (pitch_val > st->max_pitch)
+      pitch_val = st->max_pitch;
+   if (pitch_val < st->min_pitch)
+      pitch_val = st->min_pitch;
+   for (i=0;i<st->frameSize;i++)
+   {
+      st->exc[i]= MULT16_16_Q15(pitch_gain, (st->exc[i-pitch_val]+VERY_SMALL)) + 
+            speex_rand(noise_gain, &st->seed);
+   }
+
+   for (i=0;i<st->frameSize;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);
+   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++] = PSHR16(pitch_gain,9);
+   if (st->pitch_gain_buf_idx > 2) /* rollover */
+      st->pitch_gain_buf_idx = 0;
+}
+
+
+int nb_decode(void *state, SpeexBits *bits, void *vout)
+{
+   DecState *st;
+   int i, sub;
+   int pitch;
+   spx_word16_t pitch_gain[3];
+   spx_word32_t ol_gain=0;
+   int ol_pitch=0;
+   spx_word16_t ol_pitch_coef=0;
+   int best_pitch=40;
+   spx_word16_t best_pitch_gain=0;
+   int wideband;
+   int m;
+   char *stack;
+   VARDECL(spx_sig_t *innov);
+   VARDECL(spx_word32_t *exc32);
+   VARDECL(spx_coef_t *ak);
+   VARDECL(spx_lsp_t *qlsp);
+   spx_word16_t pitch_average=0;
+#ifdef EPIC_48K
+   int pitch_half[2] = {0, 0};
+   int ol_pitch_id=0;
+#endif
+   spx_word16_t *out = (spx_word16_t*)vout;
+   VARDECL(spx_lsp_t *interp_qlsp);
+
+   st=(DecState*)state;
+   stack=st->stack;
+
+   /* Check if we're in DTX mode*/
+   if (!bits && st->dtx_enabled)
+   {
+      st->submodeID=0;
+   } else 
+   {
+      /* If bits is NULL, consider the packet to be lost (what could we do anyway) */
+      if (!bits)
+      {
+         nb_decode_lost(st, out, stack);
+         return 0;
+      }
+
+      if (st->encode_submode)
+      {
+#ifdef EPIC_48K
+         if (!st->lbr_48k) {
+#endif
+
+      /* Search for next narrowband block (handle requests, skip wideband blocks) */
+      do {
+         if (speex_bits_remaining(bits)<5)
+            return -1;
+         wideband = speex_bits_unpack_unsigned(bits, 1);
+         if (wideband) /* Skip wideband block (for compatibility) */
+         {
+            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);
+            if (advance < 0)
+            {
+               speex_notify("Invalid mode encountered. The stream is corrupted.");
+               return -2;
+            } 
+            advance -= (SB_SUBMODE_BITS+1);
+            speex_bits_advance(bits, advance);
+            
+            if (speex_bits_remaining(bits)<5)
+               return -1;
+            wideband = speex_bits_unpack_unsigned(bits, 1);
+            if (wideband)
+            {
+               advance = submode = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS);
+               speex_mode_query(&speex_wb_mode, SPEEX_SUBMODE_BITS_PER_FRAME, &advance);
+               if (advance < 0)
+               {
+                  speex_notify("Invalid mode encountered. The stream is corrupted.");
+                  return -2;
+               } 
+               advance -= (SB_SUBMODE_BITS+1);
+               speex_bits_advance(bits, advance);
+               wideband = speex_bits_unpack_unsigned(bits, 1);
+               if (wideband)
+               {
+                  speex_notify("More than two wideband layers found. The stream is corrupted.");
+                  return -2;
+               }
+
+            }
+         }
+         if (speex_bits_remaining(bits)<4)
+            return -1;
+         /* FIXME: Check for overflow */
+         m = speex_bits_unpack_unsigned(bits, 4);
+         if (m==15) /* We found a terminator */
+         {
+            return -1;
+         } else if (m==14) /* Speex in-band request */
+         {
+            int ret = speex_inband_handler(bits, st->speex_callbacks, state);
+            if (ret)
+               return ret;
+         } else if (m==13) /* User in-band request */
+         {
+            int ret = st->user_callback.func(bits, state, st->user_callback.data);
+            if (ret)
+               return ret;
+         } else if (m>8) /* Invalid mode */
+         {
+            speex_notify("Invalid mode encountered. The stream is corrupted.");
+            return -2;
+         }
+      
+      } while (m>8);
+
+      /* 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));
+
+   /* 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(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;
+         /* FIXME: This was innov, not exc */
+         innov_gain = compute_rms16(st->exc, st->frameSize);
+         for (i=0;i<st->frameSize;i++)
+            st->exc[i]=speex_rand(innov_gain, &st->seed);
+      }
+
+
+      st->first=1;
+
+      for (i=0;i<st->frameSize;i++)
+         out[i] = st->exc[i];
+      /* Final signal synthesis from excitation */
+      iir_mem16(out, lpc, out, st->frameSize, st->lpcSize, st->mem_sp, stack);
+
+      st->count_lost=0;
+      return 0;
+   }
+
+   ALLOC(qlsp, st->lpcSize, spx_lsp_t);
+
+   /* Unquantize LSPs */
+   SUBMODE(lsp_unquant)(qlsp, st->lpcSize, bits);
+
+   /*Damp memory if a frame was lost and the LSP changed too much*/
+   if (st->count_lost)
+   {
+      spx_word16_t fact;
+      spx_word32_t lsp_dist=0;
+      for (i=0;i<st->lpcSize;i++)
+         lsp_dist = ADD32(lsp_dist, EXTEND32(ABS(st->old_qlsp[i] - qlsp[i])));
+#ifdef FIXED_POINT
+      fact = SHR16(19661,SHR32(lsp_dist,LSP_SHIFT+2));      
+#else
+      fact = .6*exp(-.2*lsp_dist);
+#endif
+      for (i=0;i<st->lpcSize;i++)
+         st->mem_sp[i] = MULT16_32_Q15(fact,st->mem_sp[i]);
+   }
+
+
+   /* Handle first frame and lost-packet case */
+   if (st->first || st->count_lost)
+   {
+      for (i=0;i<st->lpcSize;i++)
+         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)
+   {
+      ol_pitch = st->min_pitch+speex_bits_unpack_unsigned(bits, 7);
+   } 
+   
+   if (SUBMODE(forced_pitch_gain))
+   {
+      int quant;
+      quant = speex_bits_unpack_unsigned(bits, 4);
+      ol_pitch_coef=GAIN_SCALING*0.066667*quant;
+   }
+   
+   /* Get global excitation gain */
+   {
+      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);
+   ALLOC(exc32, st->subframeSize, spx_word32_t);
+
+   if (st->submodeID==1)
+   {
+      int extra;
+      extra = speex_bits_unpack_unsigned(bits, 4);
+
+      if (extra==15)
+         st->dtx_enabled=1;
+      else
+         st->dtx_enabled=0;
+   }
+   if (st->submodeID>1)
+      st->dtx_enabled=0;
+
+   /*Loop on subframes */
+   for (sub=0;sub<st->nbSubframes;sub++)
+   {
+      int offset;
+      spx_word16_t *exc;
+      spx_word16_t *sp;
+      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 */
+      exc=st->exc+offset;
+      /* Original signal */
+      sp=out+offset;
+      if (st->innov_save)
+         innov_save = st->innov_save+offset;
+
+
+      /* Reset excitation */
+      for (i=0;i<st->subframeSize;i++)
+         exc[i]=0;
+
+      /*Adaptive codebook contribution*/
+      if (SUBMODE(ltp_unquant))
+      {
+         int pit_min, pit_max;
+         /* Handle pitch constraints if any */
+         if (SUBMODE(lbr_pitch) != -1)
+         {
+            int margin;
+            margin = SUBMODE(lbr_pitch);
+            if (margin)
+            {
+/* GT - need optimization?
+               if (ol_pitch < st->min_pitch+margin-1)
+                  ol_pitch=st->min_pitch+margin-1;
+               if (ol_pitch > st->max_pitch-margin)
+                  ol_pitch=st->max_pitch-margin;
+               pit_min = ol_pitch-margin+1;
+               pit_max = ol_pitch+margin;
+*/
+               pit_min = ol_pitch-margin+1;
+               if (pit_min < st->min_pitch)
+		  pit_min = st->min_pitch;
+               pit_max = ol_pitch+margin;
+               if (pit_max > st->max_pitch)
+		  pit_max = st->max_pitch;
+            } else {
+               pit_min = pit_max = ol_pitch;
+            }
+         } else {
+            pit_min = st->min_pitch;
+            pit_max = st->max_pitch;
+         }
+
+
+#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
+         /* 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;
+         if ((tmp>best_pitch_gain&&ABS(2*best_pitch-pitch)>=3&&ABS(3*best_pitch-pitch)>=4&&ABS(4*best_pitch-pitch)>=5) 
+              || (tmp>MULT16_16_Q15(QCONST16(.6,15),best_pitch_gain)&&(ABS(best_pitch-2*pitch)<3||ABS(best_pitch-3*pitch)<4||ABS(best_pitch-4*pitch)<5)) 
+              || (MULT16_16_Q15(QCONST16(.67,15),tmp)>best_pitch_gain&&(ABS(2*best_pitch-pitch)<3||ABS(3*best_pitch-pitch)<4||ABS(4*best_pitch-pitch)<5)) )
+         {
+            best_pitch = pitch;
+            if (tmp > best_pitch_gain)
+               best_pitch_gain = tmp;
+         }
+      } else {
+         speex_error("No pitch prediction, what's wrong");
+      }
+      
+      /* Unquantize the innovation */
+      {
+         int q_energy;
+         spx_word32_t ener;
+         
+         for (i=0;i<st->subframeSize;i++)
+            innov[i]=0;
+
+         /* Decode sub-frame gain correction */
+         if (SUBMODE(have_subframe_gain)==3)
+         {
+            q_energy = speex_bits_unpack_unsigned(bits, 3);
+            ener = MULT16_32_Q14(exc_gain_quant_scal3[q_energy],ol_gain);
+         } else if (SUBMODE(have_subframe_gain)==1)
+         {
+            q_energy = speex_bits_unpack_unsigned(bits, 1);
+            ener = MULT16_32_Q14(exc_gain_quant_scal1[q_energy],ol_gain);
+         } else {
+            ener = ol_gain;
+         }
+                  
+         if (SUBMODE(innovation_unquant))
+         {
+            /*Fixed codebook contribution*/
+            SUBMODE(innovation_unquant)(innov, SUBMODE(innovation_params), st->subframeSize, bits, stack, &st->seed);
+            /* De-normalize innovation and update excitation */
+#ifdef FIXED_POINT
+            signal_mul(innov, innov, ener, st->subframeSize);
+#else
+            signal_mul(innov, innov, ener, st->subframeSize);
+#endif
+            /* Decode second codebook (only for some modes) */
+            if (SUBMODE(double_codebook))
+            {
+               char *tmp_stack=stack;
+               VARDECL(spx_sig_t *innov2);
+               ALLOC(innov2, st->subframeSize, spx_sig_t);
+               for (i=0;i<st->subframeSize;i++)
+                  innov2[i]=0;
+               SUBMODE(innovation_unquant)(innov2, SUBMODE(innovation_params), st->subframeSize, bits, stack, &st->seed);
+               signal_mul(innov2, innov2, MULT16_32_Q15(QCONST16(0.454545f,15),ener), st->subframeSize);
+               for (i=0;i<st->subframeSize;i++)
+                  innov[i] = ADD32(innov[i], innov2[i]);
+               stack = tmp_stack;
+            }
+            for (i=0;i<st->subframeSize;i++)
+               exc[i]=EXTRACT16(SATURATE32(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT),32767));
+            /*print_vec(exc, 40, "innov");*/
+            if (innov_save)
+            {
+               for (i=0;i<st->subframeSize;i++)
+                  innov_save[i] = EXTRACT16(PSHR32(innov[i], SIG_SHIFT));
+            }
+         } else {
+            speex_error("No fixed codebook");
+         }
+
+         /*Vocoder mode*/
+         if (st->submodeID==1) 
+         {
+            float g=ol_pitch_coef*GAIN_SCALING_1;
+
+            
+            for (i=0;i<st->subframeSize;i++)
+               exc[i]=0;
+            while (st->voc_offset<st->subframeSize)
+            {
+               if (st->voc_offset>=0)
+                  exc[st->voc_offset]=sqrt(1.0*ol_pitch);
+               st->voc_offset+=ol_pitch;
+            }
+            st->voc_offset -= st->subframeSize;
+
+            g=.5+2*(g-.6);
+            if (g<0)
+               g=0;
+            if (g>1)
+               g=1;
+            for (i=0;i<st->subframeSize;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;
+            }
+         }
+
+      }
+   }
+   
+   ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t);
+
+   if (st->lpc_enh_enabled && SUBMODE(comb_gain)>0 && !st->count_lost)
+   {
+      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;i<st->frameSize;i++)
+         out[i]=st->exc[i-st->subframeSize];
+   }
+   
+   /* If the last packet was lost, re-scale the excitation to obtain the same energy as encoded in ol_gain */
+   if (st->count_lost) 
+   {
+      spx_word16_t exc_ener;
+      spx_word32_t gain32;
+      spx_word16_t gain;
+      exc_ener = compute_rms16 (st->exc, st->frameSize);
+      gain32 = PDIV32(ol_gain, ADD16(exc_ener,1));
+#ifdef FIXED_POINT
+      if (gain32 > 32767)
+         gain32 = 32767;
+      gain = EXTRACT16(gain32);
+#else
+      if (gain32 > 2)
+         gain32=2;
+      gain = gain32;
+#endif
+      for (i=0;i<st->frameSize;i++)
+      {
+         st->exc[i] = MULT16_16_Q14(gain, st->exc[i]);
+         out[i]=st->exc[i-st->subframeSize];
+      }
+   }
+
+   /*Loop on subframes */
+   for (sub=0;sub<st->nbSubframes;sub++)
+   {
+      int offset;
+      spx_word16_t *sp;
+      spx_word16_t *exc;
+      /* Offset relative to start of frame */
+      offset = st->subframeSize*sub;
+      /* Original signal */
+      sp=out+offset;
+      /* Excitation */
+      exc=st->exc+offset;
+
+      /* LSP interpolation (quantized and unquantized) */
+      lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpcSize, sub, st->nbSubframes);
+
+      /* Make sure the LSP's are stable */
+      lsp_enforce_margin(interp_qlsp, st->lpcSize, LSP_MARGIN);
+
+      /* Compute interpolated LPCs (unquantized) */
+      lsp_to_lpc(interp_qlsp, ak, st->lpcSize, stack);
+
+      /* Compute analysis filter at w=pi */
+      {
+         spx_word32_t pi_g=LPC_SCALING;
+         for (i=0;i<st->lpcSize;i+=2)
+         {
+            /*pi_g += -st->interp_qlpc[i] +  st->interp_qlpc[i+1];*/
+            pi_g = ADD32(pi_g, SUB32(EXTEND32(ak[i+1]),EXTEND32(ak[i])));
+         }
+         st->pi_gain[sub] = pi_g;
+      }
+      
+      iir_mem16(sp, st->interp_qlpc, sp, st->subframeSize, st->lpcSize, 
+                st->mem_sp, stack);
+      
+      for (i=0;i<st->lpcSize;i++)
+         st->interp_qlpc[i] = ak[i];
+
+   }
+
+   if (st->highpass_enabled)
+      highpass(out, out, st->frameSize, (st->isWideband?HIGHPASS_WIDEBAND:HIGHPASS_NARROWBAND)|HIGHPASS_OUTPUT, st->mem_hp);
+   /*for (i=0;i<st->frameSize;i++)
+     printf ("%d\n", (int)st->frame[i]);*/
+
+   /* Store the LSPs for interpolation in the next frame */
+   for (i=0;i<st->lpcSize;i++)
+      st->old_qlsp[i] = qlsp[i];
+
+   /* The next frame will not be the first (Duh!) */
+   st->first = 0;
+   st->count_lost=0;
+   st->last_pitch = best_pitch;
+#ifdef FIXED_POINT
+   st->last_pitch_gain = PSHR16(pitch_average,2);
+#else
+   st->last_pitch_gain = .25*pitch_average;   
+#endif
+   st->pitch_gain_buf[st->pitch_gain_buf_idx++] = st->last_pitch_gain;
+   if (st->pitch_gain_buf_idx > 2) /* rollover */
+      st->pitch_gain_buf_idx = 0;
+
+   st->last_ol_gain = ol_gain;
+
+   return 0;
+}
+
+int nb_encoder_ctl(void *state, int request, void *ptr)
+{
+   EncState *st;
+   st=(EncState*)state;     
+   switch(request)
+   {
+   case SPEEX_GET_FRAME_SIZE:
+      (*(spx_int32_t*)ptr) = st->frameSize;
+      break;
+   case SPEEX_SET_LOW_MODE:
+   case SPEEX_SET_MODE:
+      st->submodeSelect = st->submodeID = (*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_GET_LOW_MODE:
+   case SPEEX_GET_MODE:
+      (*(spx_int32_t*)ptr) = st->submodeID;
+      break;
+   case SPEEX_SET_VBR:
+      st->vbr_enabled = (*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_GET_VBR:
+      (*(spx_int32_t*)ptr) = st->vbr_enabled;
+      break;
+   case SPEEX_SET_VAD:
+      st->vad_enabled = (*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_GET_VAD:
+      (*(spx_int32_t*)ptr) = st->vad_enabled;
+      break;
+   case SPEEX_SET_DTX:
+      st->dtx_enabled = (*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_GET_DTX:
+      (*(spx_int32_t*)ptr) = st->dtx_enabled;
+      break;
+   case SPEEX_SET_ABR:
+      st->abr_enabled = (*(spx_int32_t*)ptr);
+      st->vbr_enabled = st->abr_enabled!=0;
+      if (st->vbr_enabled) 
+      {
+         spx_int32_t i=10;
+         spx_int32_t rate, target;
+         float vbr_qual;
+         target = (*(spx_int32_t*)ptr);
+         while (i>=0)
+         {
+            speex_encoder_ctl(st, SPEEX_SET_QUALITY, &i);
+            speex_encoder_ctl(st, SPEEX_GET_BITRATE, &rate);
+            if (rate <= target)
+               break;
+            i--;
+         }
+         vbr_qual=i;
+         if (vbr_qual<0)
+            vbr_qual=0;
+         speex_encoder_ctl(st, SPEEX_SET_VBR_QUALITY, &vbr_qual);
+         st->abr_count=0;
+         st->abr_drift=0;
+         st->abr_drift2=0;
+      }
+      
+      break;
+   case SPEEX_GET_ABR:
+      (*(spx_int32_t*)ptr) = st->abr_enabled;
+      break;
+   case SPEEX_SET_VBR_QUALITY:
+      st->vbr_quality = (*(float*)ptr);
+      break;
+   case SPEEX_GET_VBR_QUALITY:
+      (*(float*)ptr) = st->vbr_quality;
+      break;
+   case SPEEX_SET_QUALITY:
+      {
+         int quality = (*(spx_int32_t*)ptr);
+         if (quality < 0)
+            quality = 0;
+         if (quality > 10)
+            quality = 10;
+         st->submodeSelect = st->submodeID = ((const SpeexNBMode*)(st->mode->mode))->quality_map[quality];
+      }
+      break;
+   case SPEEX_SET_COMPLEXITY:
+      st->complexity = (*(spx_int32_t*)ptr);
+      if (st->complexity<0)
+         st->complexity=0;
+      break;
+   case SPEEX_GET_COMPLEXITY:
+      (*(spx_int32_t*)ptr) = st->complexity;
+      break;
+   case SPEEX_SET_BITRATE:
+      {
+         spx_int32_t i=10;
+         spx_int32_t rate, target;
+         target = (*(spx_int32_t*)ptr);
+         while (i>=0)
+         {
+            speex_encoder_ctl(st, SPEEX_SET_QUALITY, &i);
+            speex_encoder_ctl(st, SPEEX_GET_BITRATE, &rate);
+            if (rate <= target)
+               break;
+            i--;
+         }
+      }
+      break;
+   case SPEEX_GET_BITRATE:
+      if (st->submodes[st->submodeID])
+         (*(spx_int32_t*)ptr) = st->sampling_rate*SUBMODE(bits_per_frame)/st->frameSize;
+      else
+         (*(spx_int32_t*)ptr) = st->sampling_rate*(NB_SUBMODE_BITS+1)/st->frameSize;
+      break;
+   case SPEEX_SET_SAMPLING_RATE:
+      st->sampling_rate = (*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_GET_SAMPLING_RATE:
+      (*(spx_int32_t*)ptr)=st->sampling_rate;
+      break;
+   case SPEEX_RESET_STATE:
+      {
+         int i;
+         st->bounded_pitch = 1;
+         st->first = 1;
+         for (i=0;i<st->lpcSize;i++)
+            st->old_lsp[i]=(M_PI*((float)(i+1)))/(st->lpcSize+1);
+         for (i=0;i<st->lpcSize;i++)
+            st->mem_sw[i]=st->mem_sw_whole[i]=st->mem_sp[i]=st->mem_exc[i]=0;
+         for (i=0;i<st->frameSize+st->max_pitch+1;i++)
+            st->excBuf[i]=st->swBuf[i]=0;
+         for (i=0;i<st->windowSize-st->frameSize;i++)
+            st->winBuf[i]=0;
+      }
+      break;
+   case SPEEX_SET_SUBMODE_ENCODING:
+      st->encode_submode = (*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_GET_SUBMODE_ENCODING:
+      (*(spx_int32_t*)ptr) = st->encode_submode;
+      break;
+   case SPEEX_GET_LOOKAHEAD:
+      (*(spx_int32_t*)ptr)=(st->windowSize-st->frameSize);
+      break;
+   case SPEEX_SET_PLC_TUNING:
+      st->plc_tuning = (*(spx_int32_t*)ptr);
+      if (st->plc_tuning>100)
+         st->plc_tuning=100;
+      break;
+   case SPEEX_GET_PLC_TUNING:
+      (*(spx_int32_t*)ptr)=(st->plc_tuning);
+      break;
+   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;
+   case SPEEX_SET_HIGHPASS:
+      st->highpass_enabled = (*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_GET_HIGHPASS:
+      (*(spx_int32_t*)ptr) = st->highpass_enabled;
+      break;
+
+   /* This is all internal stuff past this point */
+   case SPEEX_GET_PI_GAIN:
+      {
+         int i;
+         spx_word32_t *g = (spx_word32_t*)ptr;
+         for (i=0;i<st->nbSubframes;i++)
+            g[i]=st->pi_gain[i];
+      }
+      break;
+   case SPEEX_GET_EXC:
+      {
+         int i;
+         for (i=0;i<st->nbSubframes;i++)
+            ((spx_word16_t*)ptr)[i] = compute_rms16(st->exc+i*st->subframeSize, st->subframeSize);
+      }
+      break;
+   case SPEEX_GET_RELATIVE_QUALITY:
+      (*(float*)ptr)=st->relative_quality;
+      break;
+   case SPEEX_SET_INNOVATION_SAVE:
+      st->innov_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;
+   }
+   return 0;
+}
+
+int nb_decoder_ctl(void *state, int request, void *ptr)
+{
+   DecState *st;
+   st=(DecState*)state;
+   switch(request)
+   {
+   case SPEEX_SET_LOW_MODE:
+   case SPEEX_SET_MODE:
+      st->submodeID = (*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_GET_LOW_MODE:
+   case SPEEX_GET_MODE:
+      (*(spx_int32_t*)ptr) = st->submodeID;
+      break;
+   case SPEEX_SET_ENH:
+      st->lpc_enh_enabled = *((spx_int32_t*)ptr);
+      break;
+   case SPEEX_GET_ENH:
+      *((spx_int32_t*)ptr) = st->lpc_enh_enabled;
+      break;
+   case SPEEX_GET_FRAME_SIZE:
+      (*(spx_int32_t*)ptr) = st->frameSize;
+      break;
+   case SPEEX_GET_BITRATE:
+      if (st->submodes[st->submodeID])
+         (*(spx_int32_t*)ptr) = st->sampling_rate*SUBMODE(bits_per_frame)/st->frameSize;
+      else
+         (*(spx_int32_t*)ptr) = st->sampling_rate*(NB_SUBMODE_BITS+1)/st->frameSize;
+      break;
+   case SPEEX_SET_SAMPLING_RATE:
+      st->sampling_rate = (*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_GET_SAMPLING_RATE:
+      (*(spx_int32_t*)ptr)=st->sampling_rate;
+      break;
+   case SPEEX_SET_HANDLER:
+      {
+         SpeexCallback *c = (SpeexCallback*)ptr;
+         st->speex_callbacks[c->callback_id].func=c->func;
+         st->speex_callbacks[c->callback_id].data=c->data;
+         st->speex_callbacks[c->callback_id].callback_id=c->callback_id;
+      }
+      break;
+   case SPEEX_SET_USER_HANDLER:
+      {
+         SpeexCallback *c = (SpeexCallback*)ptr;
+         st->user_callback.func=c->func;
+         st->user_callback.data=c->data;
+         st->user_callback.callback_id=c->callback_id;
+      }
+      break;
+   case SPEEX_RESET_STATE:
+      {
+         int i;
+         for (i=0;i<st->lpcSize;i++)
+            st->mem_sp[i]=0;
+         for (i=0;i<st->frameSize + st->max_pitch + 1;i++)
+            st->excBuf[i]=0;
+      }
+      break;
+   case SPEEX_SET_SUBMODE_ENCODING:
+      st->encode_submode = (*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_GET_SUBMODE_ENCODING:
+      (*(spx_int32_t*)ptr) = st->encode_submode;
+      break;
+   case SPEEX_GET_LOOKAHEAD:
+      (*(spx_int32_t*)ptr)=st->subframeSize;
+      break;
+   case SPEEX_SET_HIGHPASS:
+      st->highpass_enabled = (*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_GET_HIGHPASS:
+      (*(spx_int32_t*)ptr) = st->highpass_enabled;
+      break;
+
+   case SPEEX_GET_PI_GAIN:
+      {
+         int i;
+         spx_word32_t *g = (spx_word32_t*)ptr;
+         for (i=0;i<st->nbSubframes;i++)
+            g[i]=st->pi_gain[i];
+      }
+      break;
+   case SPEEX_GET_EXC:
+      {
+         int i;
+         for (i=0;i<st->nbSubframes;i++)
+            ((spx_word16_t*)ptr)[i] = compute_rms16(st->exc+i*st->subframeSize, st->subframeSize);
+      }
+      break;
+   case SPEEX_GET_DTX_STATUS:
+      *((spx_int32_t*)ptr) = st->dtx_enabled;
+      break;
+   case SPEEX_SET_INNOVATION_SAVE:
+      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;
+   }
+   return 0;
+}
diff --git a/3rdparty/speex/libspeex/nb_celp.h b/3rdparty/speex/libspeex/nb_celp.h
new file mode 100644
index 0000000..1ebf717
--- /dev/null
+++ b/3rdparty/speex/libspeex/nb_celp.h
@@ -0,0 +1,205 @@
+/* Copyright (C) 2002-2006 Jean-Marc Valin */
+/**
+    @file nb_celp.h
+    @brief Narrowband CELP encoder/decoder
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef NB_CELP_H
+#define NB_CELP_H
+
+#include "modes.h"
+#include <speex/speex_bits.h>
+#include <speex/speex_callbacks.h>
+#include "vbr.h"
+#include "filters.h"
+
+#ifdef VORBIS_PSYCHO
+#include "vorbis_psy.h"
+#endif
+
+/**Structure representing the full state of the narrowband encoder*/
+typedef struct EncState {
+   const SpeexMode *mode;        /**< Mode corresponding to the state */
+   int    first;                 /**< Is this the first frame? */
+   int    frameSize;             /**< Size of frames */
+   int    subframeSize;          /**< Size of sub-frames */
+   int    nbSubframes;           /**< Number of sub-frames */
+   int    windowSize;            /**< Analysis (LPC) window length */
+   int    lpcSize;               /**< LPC order */
+   int    min_pitch;             /**< Minimum pitch value allowed */
+   int    max_pitch;             /**< Maximum pitch value allowed */
+
+   spx_word32_t cumul_gain;      /**< Product of previously used pitch gains (Q10) */
+   int    bounded_pitch;         /**< Next frame should not rely on previous frames for pitch */
+   int    ol_pitch;              /**< Open-loop pitch */
+   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;
+   float *curve;
+   float *old_curve;
+#endif
+
+   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) */
+   spx_word16_t *excBuf;         /**< Excitation buffer */
+   spx_word16_t *exc;            /**< Start of excitation frame */
+   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 */
+   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 */
+   spx_mem_t *mem_sw;            /**< Filter memory for perceptually-weighted signal */
+   spx_mem_t *mem_sw_whole;      /**< Filter memory for perceptually-weighted signal (whole frame)*/
+   spx_mem_t *mem_exc;           /**< Filter memory for excitation (whole frame) */
+   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_word16_t *innov_rms_save; /**< If non-NULL, innovation RMS is copied here */
+         
+   VBRState *vbr;                /**< State of the VBR data */
+   float  vbr_quality;           /**< Quality setting for VBR encoding */
+   float  relative_quality;      /**< Relative quality that will be needed by VBR */
+   spx_int32_t vbr_enabled;      /**< 1 for enabling VBR, 0 otherwise */
+   spx_int32_t vbr_max;          /**< Max bit-rate allowed in VBR mode */
+   int    vad_enabled;           /**< 1 for enabling VAD, 0 otherwise */
+   int    dtx_enabled;           /**< 1 for enabling DTX, 0 otherwise */
+   int    dtx_count;             /**< Number of consecutive DTX frames */
+   spx_int32_t abr_enabled;      /**< ABR setting (in bps), 0 if off */
+   float  abr_drift;
+   float  abr_drift2;
+   float  abr_count;
+   int    complexity;            /**< Complexity setting (0-10 from least complex to most complex) */
+   spx_int32_t sampling_rate;
+   int    plc_tuning;
+   int    encode_submode;
+   const SpeexSubmode * const *submodes; /**< Sub-mode data */
+   int    submodeID;             /**< Activated sub-mode */
+   int    submodeSelect;         /**< Mode chosen by the user (may differ from submodeID if VAD is on) */
+   int    isWideband;            /**< Is this used as part of the embedded wideband codec */
+   int    highpass_enabled;        /**< Is the input filter enabled */
+} EncState;
+
+/**Structure representing the full state of the narrowband decoder*/
+typedef struct DecState {
+   const SpeexMode *mode;       /**< Mode corresponding to the state */
+   int    first;                /**< Is this the first frame? */
+   int    count_lost;           /**< Was the last frame lost? */
+   int    frameSize;            /**< Size of frames */
+   int    subframeSize;         /**< Size of sub-frames */
+   int    nbSubframes;          /**< Number of sub-frames */
+   int    lpcSize;              /**< LPC order */
+   int    min_pitch;            /**< Minimum pitch value allowed */
+   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 */
+   spx_word16_t *excBuf;        /**< Excitation buffer */
+   spx_word16_t *exc;           /**< Start of excitation frame */
+   spx_lsp_t *old_qlsp;         /**< Quantized LSPs for previous frame */
+   spx_coef_t *interp_qlpc;     /**< Interpolated quantized LPCs */
+   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_word16_t *innov_save;       /** If non-NULL, innovation is copied here */
+   
+   /* This is used in packet loss concealment */
+   int    last_pitch;           /**< Pitch of last correctly decoded frame */
+   spx_word16_t  last_pitch_gain; /**< Pitch gain of last correctly decoded frame */
+   spx_word16_t  pitch_gain_buf[3]; /**< Pitch gain of last decoded frames */
+   int    pitch_gain_buf_idx;   /**< Tail of the buffer */
+   spx_int32_t seed;            /** Seed used for random number generation */
+   
+   int    encode_submode;
+   const SpeexSubmode * const *submodes; /**< Sub-mode data */
+   int    submodeID;            /**< Activated sub-mode */
+   int    lpc_enh_enabled;      /**< 1 when LPC enhancer is on, 0 otherwise */
+   SpeexCallback speex_callbacks[SPEEX_MAX_CALLBACKS];
+
+   SpeexCallback user_callback;
+
+   /*Vocoder data*/
+   spx_word16_t  voc_m1;
+   spx_word32_t  voc_m2;
+   float  voc_mean;
+   int    voc_offset;
+
+   int    dtx_enabled;
+   int    isWideband;            /**< Is this used as part of the embedded wideband codec */
+   int    highpass_enabled;        /**< Is the input filter enabled */
+} DecState;
+
+/** Initializes encoder state*/
+void *nb_encoder_init(const SpeexMode *m);
+
+/** De-allocates encoder state resources*/
+void nb_encoder_destroy(void *state);
+
+/** Encodes one frame*/
+int nb_encode(void *state, void *in, SpeexBits *bits);
+
+
+/** Initializes decoder state*/
+void *nb_decoder_init(const SpeexMode *m);
+
+/** De-allocates decoder state resources*/
+void nb_decoder_destroy(void *state);
+
+/** Decodes one frame*/
+int nb_decode(void *state, SpeexBits *bits, void *out);
+
+/** ioctl-like function for controlling a narrowband encoder */
+int nb_encoder_ctl(void *state, int request, void *ptr);
+
+/** ioctl-like function for controlling a narrowband decoder */
+int nb_decoder_ctl(void *state, int request, void *ptr);
+
+
+#endif
diff --git a/3rdparty/speex/libspeex/preprocess.c b/3rdparty/speex/libspeex/preprocess.c
new file mode 100644
index 0000000..b5caf4b
--- /dev/null
+++ b/3rdparty/speex/libspeex/preprocess.c
@@ -0,0 +1,1172 @@
+/* Copyright (C) 2003 Epic Games (written by Jean-Marc Valin)
+   Copyright (C) 2004-2006 Epic Games 
+   
+   File: preprocess.c
+   Preprocessor with denoising based on the algorithm by Ephraim and Malah
+
+   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.
+*/
+
+
+/*
+   Recommended papers:
+   
+   Y. Ephraim and D. Malah, "Speech enhancement using minimum mean-square error
+   short-time spectral amplitude estimator". IEEE Transactions on Acoustics, 
+   Speech and Signal Processing, vol. ASSP-32, no. 6, pp. 1109-1121, 1984.
+   
+   Y. Ephraim and D. Malah, "Speech enhancement using minimum mean-square error
+   log-spectral amplitude estimator". IEEE Transactions on Acoustics, Speech and 
+   Signal Processing, vol. ASSP-33, no. 2, pp. 443-445, 1985.
+   
+   I. Cohen and B. Berdugo, "Speech enhancement for non-stationary noise environments".
+   Signal Processing, vol. 81, no. 2, pp. 2403-2418, 2001.
+
+   Stefan Gustafsson, Rainer Martin, Peter Jax, and Peter Vary. "A psychoacoustic 
+   approach to combined acoustic echo cancellation and noise reduction". IEEE 
+   Transactions on Speech and Audio Processing, 2002.
+   
+   J.-M. Valin, J. Rouat, and F. Michaud, "Microphone array post-filter for separation
+   of simultaneous non-stationary sources". In Proceedings IEEE International 
+   Conference on Acoustics, Speech, and Signal Processing, 2004.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include "speex/speex_preprocess.h"
+#include "speex/speex_echo.h"
+#include "misc.h"
+#include "fftwrap.h"
+#include "filterbank.h"
+#include "math_approx.h"
+
+#ifndef M_PI
+#define M_PI 3.14159263
+#endif
+
+#define LOUDNESS_EXP 5.f
+#define AMP_SCALE .001f
+#define AMP_SCALE_1 1000.f
+      
+#define NB_BANDS 24
+
+#define SPEECH_PROB_START_DEFAULT       QCONST16(0.35f,15)
+#define SPEECH_PROB_CONTINUE_DEFAULT    QCONST16(0.20f,15)
+#define NOISE_SUPPRESS_DEFAULT       -15
+#define ECHO_SUPPRESS_DEFAULT        -40
+#define ECHO_SUPPRESS_ACTIVE_DEFAULT -15
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define SQR(x) ((x)*(x))
+#define SQR16(x) (MULT16_16((x),(x)))
+#define SQR16_Q15(x) (MULT16_16_Q15((x),(x)))
+
+#ifdef FIXED_POINT
+static inline spx_word16_t DIV32_16_Q8(spx_word32_t a, spx_word32_t b)
+{
+   if (SHR32(a,7) >= b)
+   {
+      return 32767;
+   } else {
+      if (b>=QCONST32(1,23))
+      {
+         a = SHR32(a,8);
+         b = SHR32(b,8);
+      }
+      if (b>=QCONST32(1,19))
+      {
+         a = SHR32(a,4);
+         b = SHR32(b,4);
+      }
+      if (b>=QCONST32(1,15))
+      {
+         a = SHR32(a,4);
+         b = SHR32(b,4);
+      }
+      a = SHL32(a,8);
+      return PDIV32_16(a,b);
+   }
+   
+}
+static inline spx_word16_t DIV32_16_Q15(spx_word32_t a, spx_word32_t b)
+{
+   if (SHR32(a,15) >= b)
+   {
+      return 32767;
+   } else {
+      if (b>=QCONST32(1,23))
+      {
+         a = SHR32(a,8);
+         b = SHR32(b,8);
+      }
+      if (b>=QCONST32(1,19))
+      {
+         a = SHR32(a,4);
+         b = SHR32(b,4);
+      }
+      if (b>=QCONST32(1,15))
+      {
+         a = SHR32(a,4);
+         b = SHR32(b,4);
+      }
+      a = SHL32(a,15)-a;
+      return DIV32_16(a,b);
+   }
+}
+#define SNR_SCALING 256.f
+#define SNR_SCALING_1 0.0039062f
+#define SNR_SHIFT 8
+
+#define FRAC_SCALING 32767.f
+#define FRAC_SCALING_1 3.0518e-05
+#define FRAC_SHIFT 1
+
+#define EXPIN_SCALING 2048.f
+#define EXPIN_SCALING_1 0.00048828f
+#define EXPIN_SHIFT 11
+#define EXPOUT_SCALING_1 1.5259e-05
+
+#define NOISE_SHIFT 7
+
+#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;
+   
+   /* DSP-related arrays */
+   spx_word16_t *frame;      /**< Processing frame (2*ps_size) */
+   spx_word16_t *ft;         /**< Processing frame in freq domain (2*ps_size) */
+   spx_word32_t *ps;         /**< Current power spectrum */
+   spx_word16_t *gain2;      /**< Adjusted gains */
+   spx_word16_t *gain_floor; /**< Minimum gain allowed */
+   spx_word16_t *window;     /**< Analysis/Synthesis window */
+   spx_word32_t *noise;      /**< Noise estimate */
+   spx_word32_t *reverb_estimate; /**< Estimate of reverb energy */
+   spx_word32_t *old_ps;     /**< Power spectrum for last frame */
+   spx_word16_t *gain;       /**< Ephraim Malah gain */
+   spx_word16_t *prior;      /**< A-priori SNR */
+   spx_word16_t *post;       /**< A-posteriori SNR */
+
+   spx_word32_t *S;          /**< Smoothed power spectrum */
+   spx_word32_t *Smin;       /**< See Cohen paper */
+   spx_word32_t *Stmp;       /**< See Cohen paper */
+   int *update_prob;       /**< Propability of speech presence for noise update */
+
+   spx_word16_t *zeta;       /**< Smoothed a priori SNR */
+   spx_word32_t *echo_noise;
+   spx_word32_t *residual_echo;
+
+   /* Misc */
+   spx_word16_t *inbuf;      /**< Input buffer (overlapped analysis) */
+   spx_word16_t *outbuf;     /**< Output buffer (for overlap and add) */
+
+   /* AGC stuff, only for floating point for now */
+#ifndef FIXED_POINT
+   int    agc_enabled;
+   float  agc_level;
+   float  loudness_accum;
+   float *loudness_weight;   /**< Perceptual loudness curve */
+   float  loudness;          /**< Loudness estimate */
+   float  agc_gain;          /**< Current AGC gain */
+   int    nb_loudness_adapt; /**< Number of frames used for loudness adaptation so far */
+   float  max_gain;          /**< Maximum gain allowed */
+   float  max_increase_step; /**< Maximum increase in gain from one frame to another */
+   float  max_decrease_step; /**< Maximum decrease in gain from one frame to another */
+   float  prev_loudness;     /**< Loudness of previous frame */
+   float  init_max;          /**< Current gain limit during initialisation */
+#endif
+   int    nb_adapt;          /**< Number of frames used for adaptation so far */
+   int    was_speech;
+   int    min_count;         /**< Number of frames processed so far */
+   void  *fft_lookup;        /**< Lookup table for the FFT */
+#ifdef FIXED_POINT
+   int    frame_shift;
+#endif
+};
+
+
+static void conj_window(spx_word16_t *w, int len)
+{
+   int i;
+   for (i=0;i<len;i++)
+   {
+      spx_word16_t tmp;
+#ifdef FIXED_POINT
+      spx_word16_t x = DIV32_16(MULT16_16(32767,i),len);
+#else      
+      spx_word16_t x = DIV32_16(MULT16_16(QCONST16(4.f,13),i),len);
+#endif
+      int inv=0;
+      if (x<QCONST16(1.f,13))
+      {
+      } else if (x<QCONST16(2.f,13))
+      {
+         x=QCONST16(2.f,13)-x;
+         inv=1;
+      } else if (x<QCONST16(3.f,13))
+      {
+         x=x-QCONST16(2.f,13);
+         inv=1;
+      } else {
+         x=QCONST16(2.f,13)-x+QCONST16(2.f,13); /* 4 - x */
+      }
+      x = MULT16_16_Q14(QCONST16(1.271903f,14), x);
+      tmp = SQR16_Q15(QCONST16(.5f,15)-MULT16_16_P15(QCONST16(.5f,15),spx_cos_norm(QCONST32(x,2))));
+      if (inv)
+         tmp=SUB16(Q15_ONE,tmp);
+      w[i]=spx_sqrt(SHL32(EXTEND32(tmp),15));
+   }
+}
+
+      
+#ifdef FIXED_POINT
+/* This function approximates the gain function 
+   y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x)  
+   which multiplied by xi/(1+xi) is the optimal gain
+   in the loudness domain ( sqrt[amplitude] )
+   Input in Q11 format, output in Q15
+*/
+static inline spx_word32_t hypergeom_gain(spx_word32_t xx)
+{
+   int ind;
+   spx_word16_t frac;
+   /* Q13 table */
+   static const spx_word16_t table[21] = {
+       6730,  8357,  9868, 11267, 12563, 13770, 14898,
+      15959, 16961, 17911, 18816, 19682, 20512, 21311,
+      22082, 22827, 23549, 24250, 24931, 25594, 26241};
+      ind = SHR32(xx,10);
+      if (ind<0)
+         return Q15_ONE;
+      if (ind>19)
+         return ADD32(EXTEND32(Q15_ONE),EXTEND32(DIV32_16(QCONST32(.1296,23), SHR32(xx,EXPIN_SHIFT-SNR_SHIFT))));
+      frac = SHL32(xx-SHL32(ind,10),5);
+      return SHL32(DIV32_16(PSHR32(MULT16_16(Q15_ONE-frac,table[ind]) + MULT16_16(frac,table[ind+1]),7),(spx_sqrt(SHL32(xx,15)+6711))),7);
+}
+
+static inline spx_word16_t qcurve(spx_word16_t x)
+{
+   x = MAX16(x, 1);
+   return DIV32_16(SHL32(EXTEND32(32767),9),ADD16(512,MULT16_16_Q15(QCONST16(.60f,15),DIV32_16(32767,x))));
+}
+
+/* Compute the gain floor based on different floors for the background noise and residual echo */
+static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, spx_word32_t *noise, spx_word32_t *echo, spx_word16_t *gain_floor, int len)
+{
+   int i;
+   
+   if (noise_suppress > effective_echo_suppress)
+   {
+      spx_word16_t noise_gain, gain_ratio;
+      noise_gain = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(0.11513,11),noise_suppress)),1)));
+      gain_ratio = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(.2302585f,11),effective_echo_suppress-noise_suppress)),1)));
+
+      /* gain_floor = sqrt [ (noise*noise_floor + echo*echo_floor) / (noise+echo) ] */
+      for (i=0;i<len;i++)
+         gain_floor[i] = MULT16_16_Q15(noise_gain,
+                                       spx_sqrt(SHL32(EXTEND32(DIV32_16_Q15(PSHR32(noise[i],NOISE_SHIFT) + MULT16_32_Q15(gain_ratio,echo[i]),
+                                             (1+PSHR32(noise[i],NOISE_SHIFT) + echo[i]) )),15)));
+   } else {
+      spx_word16_t echo_gain, gain_ratio;
+      echo_gain = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(0.11513,11),effective_echo_suppress)),1)));
+      gain_ratio = EXTRACT16(MIN32(Q15_ONE,SHR32(spx_exp(MULT16_16(QCONST16(.2302585f,11),noise_suppress-effective_echo_suppress)),1)));
+
+      /* gain_floor = sqrt [ (noise*noise_floor + echo*echo_floor) / (noise+echo) ] */
+      for (i=0;i<len;i++)
+         gain_floor[i] = MULT16_16_Q15(echo_gain,
+                                       spx_sqrt(SHL32(EXTEND32(DIV32_16_Q15(MULT16_32_Q15(gain_ratio,PSHR32(noise[i],NOISE_SHIFT)) + echo[i],
+                                             (1+PSHR32(noise[i],NOISE_SHIFT) + echo[i]) )),15)));
+   }
+}
+
+#else
+/* This function approximates the gain function 
+   y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x)  
+   which multiplied by xi/(1+xi) is the optimal gain
+   in the loudness domain ( sqrt[amplitude] )
+*/
+static inline spx_word32_t hypergeom_gain(spx_word32_t xx)
+{
+   int ind;
+   float integer, frac;
+   float x;
+   static const float table[21] = {
+      0.82157f, 1.02017f, 1.20461f, 1.37534f, 1.53363f, 1.68092f, 1.81865f,
+      1.94811f, 2.07038f, 2.18638f, 2.29688f, 2.40255f, 2.50391f, 2.60144f,
+      2.69551f, 2.78647f, 2.87458f, 2.96015f, 3.04333f, 3.12431f, 3.20326f};
+      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 spx_word16_t qcurve(spx_word16_t x)
+{
+   return 1.f/(1.f+.15f/(SNR_SCALING_1*x));
+}
+
+static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, spx_word32_t *noise, spx_word32_t *echo, spx_word16_t *gain_floor, int len)
+{
+   int i;
+   float echo_floor;
+   float noise_floor;
+
+   noise_floor = exp(.2302585f*noise_suppress);
+   echo_floor = exp(.2302585f*effective_echo_suppress);
+
+   /* Compute the gain floor based on different floors for the background noise and residual echo */
+   for (i=0;i<len;i++)
+      gain_floor[i] = FRAC_SCALING*sqrt(noise_floor*PSHR32(noise[i],NOISE_SHIFT) + echo_floor*echo[i])/sqrt(1+PSHR32(noise[i],NOISE_SHIFT) + echo[i]);
+}
+
+#endif
+SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate)
+{
+   int i;
+   int N, N3, N4, M;
+
+   SpeexPreprocessState *st = (SpeexPreprocessState *)speex_alloc(sizeof(SpeexPreprocessState));
+   st->frame_size = frame_size;
+
+   /* Round ps_size down to the nearest power of two */
+#if 0
+   i=1;
+   st->ps_size = st->frame_size;
+   while(1)
+   {
+      if (st->ps_size & ~i)
+      {
+         st->ps_size &= ~i;
+         i<<=1;
+      } else {
+         break;
+      }
+   }
+   
+   
+   if (st->ps_size < 3*st->frame_size/4)
+      st->ps_size = st->ps_size * 3 / 2;
+#else
+   st->ps_size = st->frame_size;
+#endif
+
+   N = st->ps_size;
+   N3 = 2*N - st->frame_size;
+   N4 = st->frame_size - N3;
+   
+   st->sampling_rate = sampling_rate;
+   st->denoise_enabled = 1;
+   st->vad_enabled = 0;
+   st->dereverb_enabled = 0;
+   st->reverb_decay = 0;
+   st->reverb_level = 0;
+   st->noise_suppress = NOISE_SUPPRESS_DEFAULT;
+   st->echo_suppress = ECHO_SUPPRESS_DEFAULT;
+   st->echo_suppress_active = ECHO_SUPPRESS_ACTIVE_DEFAULT;
+
+   st->speech_prob_start = SPEECH_PROB_START_DEFAULT;
+   st->speech_prob_continue = SPEECH_PROB_CONTINUE_DEFAULT;
+
+   st->echo_state = NULL;
+   
+   st->nbands = NB_BANDS;
+   M = st->nbands;
+   st->bank = filterbank_new(M, sampling_rate, N, 1);
+   
+   st->frame = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t));
+   st->window = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t));
+   st->ft = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t));
+   
+   st->ps = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t));
+   st->noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t));
+   st->echo_noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t));
+   st->residual_echo = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t));
+   st->reverb_estimate = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t));
+   st->old_ps = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t));
+   st->prior = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t));
+   st->post = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t));
+   st->gain = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t));
+   st->gain2 = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t));
+   st->gain_floor = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t));
+   st->zeta = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t));
+   
+   st->S = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t));
+   st->Smin = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t));
+   st->Stmp = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t));
+   st->update_prob = (int*)speex_alloc(N*sizeof(int));
+   
+   st->inbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t));
+   st->outbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t));
+
+   conj_window(st->window, 2*N3);
+   for (i=2*N3;i<2*st->ps_size;i++)
+      st->window[i]=Q15_ONE;
+   
+   if (N4>0)
+   {
+      for (i=N3-1;i>=0;i--)
+      {
+         st->window[i+N3+N4]=st->window[i+N3];
+         st->window[i+N3]=1;
+      }
+   }
+   for (i=0;i<N+M;i++)
+   {
+      st->noise[i]=QCONST32(1.f,NOISE_SHIFT);
+      st->reverb_estimate[i]=0;
+      st->old_ps[i]=1;
+      st->gain[i]=Q15_ONE;
+      st->post[i]=SHL16(1, SNR_SHIFT);
+      st->prior[i]=SHL16(1, SNR_SHIFT);
+   }
+
+   for (i=0;i<N;i++)
+      st->update_prob[i] = 1;
+   for (i=0;i<N3;i++)
+   {
+      st->inbuf[i]=0;
+      st->outbuf[i]=0;
+   }
+#ifndef FIXED_POINT
+   st->agc_enabled = 0;
+   st->agc_level = 8000;
+   st->loudness_weight = (float*)speex_alloc(N*sizeof(float));
+   for (i=0;i<N;i++)
+   {
+      float ff=((float)i)*.5*sampling_rate/((float)N);
+      /*st->loudness_weight[i] = .5f*(1.f/(1.f+ff/8000.f))+1.f*exp(-.5f*(ff-3800.f)*(ff-3800.f)/9e5f);*/
+      st->loudness_weight[i] = .35f-.35f*ff/16000.f+.73f*exp(-.5f*(ff-3800)*(ff-3800)/9e5f);
+      if (st->loudness_weight[i]<.01f)
+         st->loudness_weight[i]=.01f;
+      st->loudness_weight[i] *= st->loudness_weight[i];
+   }
+   /*st->loudness = pow(AMP_SCALE*st->agc_level,LOUDNESS_EXP);*/
+   st->loudness = 1e-15;
+   st->agc_gain = 1;
+   st->nb_loudness_adapt = 0;
+   st->max_gain = 30;
+   st->max_increase_step = exp(0.11513f * 12.*st->frame_size / st->sampling_rate);
+   st->max_decrease_step = exp(-0.11513f * 40.*st->frame_size / st->sampling_rate);
+   st->prev_loudness = 1;
+   st->init_max = 1;
+#endif
+   st->was_speech = 0;
+
+   st->fft_lookup = spx_fft_init(2*N);
+
+   st->nb_adapt=0;
+   st->min_count=0;
+   return st;
+}
+
+void speex_preprocess_state_destroy(SpeexPreprocessState *st)
+{
+   speex_free(st->frame);
+   speex_free(st->ft);
+   speex_free(st->ps);
+   speex_free(st->gain2);
+   speex_free(st->gain_floor);
+   speex_free(st->window);
+   speex_free(st->noise);
+   speex_free(st->reverb_estimate);
+   speex_free(st->old_ps);
+   speex_free(st->gain);
+   speex_free(st->prior);
+   speex_free(st->post);
+#ifndef FIXED_POINT
+   speex_free(st->loudness_weight);
+#endif
+   speex_free(st->echo_noise);
+   speex_free(st->residual_echo);
+
+   speex_free(st->S);
+   speex_free(st->Smin);
+   speex_free(st->Stmp);
+   speex_free(st->update_prob);
+   speex_free(st->zeta);
+
+   speex_free(st->inbuf);
+   speex_free(st->outbuf);
+
+   spx_fft_destroy(st->fft_lookup);
+   filterbank_destroy(st->bank);
+   speex_free(st);
+}
+
+/* FIXME: The AGC doesn't work yet with fixed-point*/
+#ifndef FIXED_POINT
+static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx_word16_t *ft)
+{
+   int i;
+   int N = st->ps_size;
+   float target_gain;
+   float loudness=1.f;
+   float rate;
+   
+   for (i=2;i<N;i++)
+   {
+      loudness += 2.f*N*st->ps[i]* st->loudness_weight[i];
+   }
+   loudness=sqrt(loudness);
+      /*if (loudness < 2*pow(st->loudness, 1.0/LOUDNESS_EXP) &&
+   loudness*2 > pow(st->loudness, 1.0/LOUDNESS_EXP))*/
+   if (Pframe>.3f)
+   {
+      st->nb_loudness_adapt++;
+      /*rate=2.0f*Pframe*Pframe/(1+st->nb_loudness_adapt);*/
+      rate = .03*Pframe*Pframe;
+      st->loudness = (1-rate)*st->loudness + (rate)*pow(AMP_SCALE*loudness, LOUDNESS_EXP);
+      st->loudness_accum = (1-rate)*st->loudness_accum + rate;
+      if (st->init_max < st->max_gain && st->nb_adapt > 20)
+         st->init_max *= 1.f + .1f*Pframe*Pframe;
+   }
+   /*printf ("%f %f %f %f\n", Pframe, loudness, pow(st->loudness, 1.0f/LOUDNESS_EXP), st->loudness2);*/
+   
+   target_gain = AMP_SCALE*st->agc_level*pow(st->loudness/(1e-4+st->loudness_accum), -1.0f/LOUDNESS_EXP);
+
+   if ((Pframe>.5  && st->nb_adapt > 20) || target_gain < st->agc_gain)
+   {
+      if (target_gain > st->max_increase_step*st->agc_gain)
+         target_gain = st->max_increase_step*st->agc_gain;
+      if (target_gain < st->max_decrease_step*st->agc_gain && loudness < 10*st->prev_loudness)
+         target_gain = st->max_decrease_step*st->agc_gain;
+      if (target_gain > st->max_gain)
+         target_gain = st->max_gain;
+      if (target_gain > st->init_max)
+         target_gain = st->init_max;
+   
+      st->agc_gain = target_gain;
+   }
+   /*fprintf (stderr, "%f %f %f\n", loudness, (float)AMP_SCALE_1*pow(st->loudness, 1.0f/LOUDNESS_EXP), st->agc_gain);*/
+      
+   for (i=0;i<2*N;i++)
+      ft[i] *= st->agc_gain;
+   st->prev_loudness = loudness;
+}
+#endif
+
+static void preprocess_analysis(SpeexPreprocessState *st, spx_int16_t *x)
+{
+   int i;
+   int N = st->ps_size;
+   int N3 = 2*N - st->frame_size;
+   int N4 = st->frame_size - N3;
+   spx_word32_t *ps=st->ps;
+
+   /* 'Build' input frame */
+   for (i=0;i<N3;i++)
+      st->frame[i]=st->inbuf[i];
+   for (i=0;i<st->frame_size;i++)
+      st->frame[N3+i]=x[i];
+   
+   /* Update inbuf */
+   for (i=0;i<N3;i++)
+      st->inbuf[i]=x[N4+i];
+
+   /* Windowing */
+   for (i=0;i<2*N;i++)
+      st->frame[i] = MULT16_16_Q15(st->frame[i], st->window[i]);
+
+#ifdef FIXED_POINT
+   {
+      spx_word16_t max_val=0;
+      for (i=0;i<2*N;i++)
+         max_val = MAX16(max_val, ABS16(st->frame[i]));
+      st->frame_shift = 14-spx_ilog2(EXTEND32(max_val));
+      for (i=0;i<2*N;i++)
+         st->frame[i] = SHL16(st->frame[i], st->frame_shift);
+   }
+#endif
+   
+   /* Perform FFT */
+   spx_fft(st->fft_lookup, st->frame, st->ft);
+         
+   /* Power spectrum */
+   ps[0]=MULT16_16(st->ft[0],st->ft[0]);
+   for (i=1;i<N;i++)
+      ps[i]=MULT16_16(st->ft[2*i-1],st->ft[2*i-1]) + MULT16_16(st->ft[2*i],st->ft[2*i]);
+   for (i=0;i<N;i++)
+      st->ps[i] = PSHR32(st->ps[i], 2*st->frame_shift);
+
+   filterbank_compute_bank32(st->bank, ps, ps+N);
+}
+
+static void update_noise_prob(SpeexPreprocessState *st)
+{
+   int i;
+   int min_range;
+   int N = st->ps_size;
+
+   for (i=1;i<N-1;i++)
+      st->S[i] =  MULT16_32_Q15(QCONST16(.8f,15),st->S[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i-1]) 
+                      + MULT16_32_Q15(QCONST16(.1f,15),st->ps[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i+1]);
+   st->S[0] =  MULT16_32_Q15(QCONST16(.8f,15),st->S[0]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[0]);
+   st->S[N-1] =  MULT16_32_Q15(QCONST16(.8f,15),st->S[N-1]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[N-1]);
+   
+   if (st->nb_adapt==1)
+   {
+      for (i=0;i<N;i++)
+         st->Smin[i] = st->Stmp[i] = 0;
+   }
+
+   if (st->nb_adapt < 100)
+      min_range = 15;
+   else if (st->nb_adapt < 1000)
+      min_range = 50;
+   else if (st->nb_adapt < 10000)
+      min_range = 150;
+   else
+      min_range = 300;
+   if (st->min_count > min_range)
+   {
+      st->min_count = 0;
+      for (i=0;i<N;i++)
+      {
+         st->Smin[i] = MIN32(st->Stmp[i], st->S[i]);
+         st->Stmp[i] = st->S[i];
+      }
+   } else {
+      for (i=0;i<N;i++)
+      {
+         st->Smin[i] = MIN32(st->Smin[i], st->S[i]);
+         st->Stmp[i] = MIN32(st->Stmp[i], st->S[i]);      
+      }
+   }
+   for (i=0;i<N;i++)
+   {
+      if (MULT16_32_Q15(QCONST16(.4f,15),st->S[i]) > ADD32(st->Smin[i],EXTEND32(20)))
+         st->update_prob[i] = 1;
+      else
+         st->update_prob[i] = 0;
+      /*fprintf (stderr, "%f ", st->S[i]/st->Smin[i]);*/
+      /*fprintf (stderr, "%f ", st->update_prob[i]);*/
+   }
+
+}
+
+#define NOISE_OVERCOMPENS 1.
+
+void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len);
+
+int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo)
+{
+   return speex_preprocess_run(st, x);
+}
+
+int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
+{
+   int i;
+   int M;
+   int N = st->ps_size;
+   int N3 = 2*N - st->frame_size;
+   int N4 = st->frame_size - N3;
+   spx_word32_t *ps=st->ps;
+   spx_word32_t Zframe;
+   spx_word16_t Pframe;
+   spx_word16_t beta, beta_1;
+   spx_word16_t effective_echo_suppress;
+   
+   st->nb_adapt++;
+   st->min_count++;
+   
+   beta = MAX16(QCONST16(.03,15),DIV32_16(Q15_ONE,st->nb_adapt));
+   beta_1 = Q15_ONE-beta;
+   M = st->nbands;
+   /* Deal with residual echo if provided */
+   if (st->echo_state)
+   {
+      speex_echo_get_residual(st->echo_state, st->residual_echo, N);
+#ifndef FIXED_POINT
+      /* If there are NaNs or ridiculous values, it'll show up in the DC and we just reset everything to zero */
+      if (!(st->residual_echo[0] >=0 && st->residual_echo[0]<N*1e9f))
+      {
+         for (i=0;i<N;i++)
+            st->residual_echo[i] = 0;
+      }
+#endif
+      for (i=0;i<N;i++)
+         st->echo_noise[i] = MAX32(MULT16_32_Q15(QCONST16(.6f,15),st->echo_noise[i]), st->residual_echo[i]);
+      filterbank_compute_bank32(st->bank, st->echo_noise, st->echo_noise+N);
+   } else {
+      for (i=0;i<N+M;i++)
+         st->echo_noise[i] = 0;
+   }
+   preprocess_analysis(st, x);
+
+   update_noise_prob(st);
+
+   /* Noise estimation always updated for the 10 first frames */
+   /*if (st->nb_adapt<10)
+   {
+      for (i=1;i<N-1;i++)
+         st->update_prob[i] = 0;
+   }
+   */
+   
+   /* Update the noise estimate for the frequencies where it can be */
+   for (i=0;i<N;i++)
+   {
+      if (!st->update_prob[i] || st->ps[i] < PSHR32(st->noise[i], NOISE_SHIFT))
+         st->noise[i] = MAX32(EXTEND32(0),MULT16_32_Q15(beta_1,st->noise[i]) + MULT16_32_Q15(beta,SHL32(st->ps[i],NOISE_SHIFT)));
+   }
+   filterbank_compute_bank32(st->bank, st->noise, st->noise+N);
+
+   /* Special case for first frame */
+   if (st->nb_adapt==1)
+      for (i=0;i<N+M;i++)
+         st->old_ps[i] = ps[i];
+
+   /* Compute a posteriori SNR */
+   for (i=0;i<N+M;i++)
+   {
+      spx_word16_t gamma;
+      
+      /* Total noise estimate including residual echo and reverberation */
+      spx_word32_t tot_noise = ADD32(ADD32(ADD32(EXTEND32(1), PSHR32(st->noise[i],NOISE_SHIFT)) , st->echo_noise[i]) , st->reverb_estimate[i]);
+      
+      /* A posteriori SNR = ps/noise - 1*/
+      st->post[i] = SUB16(DIV32_16_Q8(ps[i],tot_noise), QCONST16(1.f,SNR_SHIFT));
+      st->post[i]=MIN16(st->post[i], QCONST16(100.f,SNR_SHIFT));
+      
+      /* Computing update gamma = .1 + .9*(old/(old+noise))^2 */
+      gamma = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.89f,15),SQR16_Q15(DIV32_16_Q15(st->old_ps[i],ADD32(st->old_ps[i],tot_noise))));
+      
+      /* A priori SNR update = gamma*max(0,post) + (1-gamma)*old/noise */
+      st->prior[i] = EXTRACT16(PSHR32(ADD32(MULT16_16(gamma,MAX16(0,st->post[i])), MULT16_16(Q15_ONE-gamma,DIV32_16_Q8(st->old_ps[i],tot_noise))), 15));
+      st->prior[i]=MIN16(st->prior[i], QCONST16(100.f,SNR_SHIFT));
+   }
+
+   /*print_vec(st->post, N+M, "");*/
+
+   /* Recursive average of the a priori SNR. A bit smoothed for the psd components */
+   st->zeta[0] = PSHR32(ADD32(MULT16_16(QCONST16(.7f,15),st->zeta[0]), MULT16_16(QCONST16(.3f,15),st->prior[0])),15);
+   for (i=1;i<N-1;i++)
+      st->zeta[i] = PSHR32(ADD32(ADD32(ADD32(MULT16_16(QCONST16(.7f,15),st->zeta[i]), MULT16_16(QCONST16(.15f,15),st->prior[i])),
+                           MULT16_16(QCONST16(.075f,15),st->prior[i-1])), MULT16_16(QCONST16(.075f,15),st->prior[i+1])),15);
+   for (i=N-1;i<N+M;i++)
+      st->zeta[i] = PSHR32(ADD32(MULT16_16(QCONST16(.7f,15),st->zeta[i]), MULT16_16(QCONST16(.3f,15),st->prior[i])),15);
+
+   /* Speech probability of presence for the entire frame is based on the average filterbank a priori SNR */
+   Zframe = 0;
+   for (i=N;i<N+M;i++)
+      Zframe = ADD32(Zframe, EXTEND32(st->zeta[i]));
+   Pframe = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.899f,15),qcurve(DIV32_16(Zframe,st->nbands)));
+   
+   effective_echo_suppress = EXTRACT16(PSHR32(ADD32(MULT16_16(SUB16(Q15_ONE,Pframe), st->echo_suppress), MULT16_16(Pframe, st->echo_suppress_active)),15));
+   
+   compute_gain_floor(st->noise_suppress, effective_echo_suppress, st->noise+N, st->echo_noise+N, st->gain_floor+N, M);
+         
+   /* Compute Ephraim & Malah gain speech probability of presence for each critical band (Bark scale) 
+      Technically this is actually wrong because the EM gaim assumes a slightly different probability 
+      distribution */
+   for (i=N;i<N+M;i++)
+   {
+      /* See EM and Cohen papers*/
+      spx_word32_t theta;
+      /* Gain from hypergeometric function */
+      spx_word32_t MM;
+      /* Weiner filter gain */
+      spx_word16_t prior_ratio;
+      /* a priority probability of speech presence based on Bark sub-band alone */
+      spx_word16_t P1;
+      /* Speech absence a priori probability (considering sub-band and frame) */
+      spx_word16_t q;
+#ifdef FIXED_POINT
+      spx_word16_t tmp;
+#endif
+      
+      prior_ratio = PDIV32_16(SHL32(EXTEND32(st->prior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT)));
+      theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT));
+
+      MM = hypergeom_gain(theta);
+      /* Gain with bound */
+      st->gain[i] = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM)));
+      /* Save old Bark power spectrum */
+      st->old_ps[i] = MULT16_32_P15(QCONST16(.2f,15),st->old_ps[i]) + MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(st->gain[i])),ps[i]);
+
+      P1 = QCONST16(.199f,15)+MULT16_16_Q15(QCONST16(.8f,15),qcurve (st->zeta[i]));
+      q = Q15_ONE-MULT16_16_Q15(Pframe,P1);
+#ifdef FIXED_POINT
+      theta = MIN32(theta, EXTEND32(32767));
+/*Q8*/tmp = MULT16_16_Q15((SHL32(1,SNR_SHIFT)+st->prior[i]),EXTRACT16(MIN32(Q15ONE,SHR32(spx_exp(-EXTRACT16(theta)),1))));
+      tmp = MIN16(QCONST16(3.,SNR_SHIFT), tmp); /* Prevent overflows in the next line*/
+/*Q8*/tmp = EXTRACT16(PSHR32(MULT16_16(PDIV32_16(SHL32(EXTEND32(q),8),(Q15_ONE-q)),tmp),8));
+      st->gain2[i]=DIV32_16(SHL32(EXTEND32(32767),SNR_SHIFT), ADD16(256,tmp));
+#else
+      st->gain2[i]=1/(1.f + (q/(1.f-q))*(1+st->prior[i])*exp(-theta));
+#endif
+   }
+   /* Convert the EM gains and speech prob to linear frequency */
+   filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2);
+   filterbank_compute_psd16(st->bank,st->gain+N, st->gain);
+   
+   /* Use 1 for linear gain resolution (best) or 0 for Bark gain resolution (faster) */
+   if (1)
+   {
+      filterbank_compute_psd16(st->bank,st->gain_floor+N, st->gain_floor);
+   
+      /* Compute gain according to the Ephraim-Malah algorithm -- linear frequency */
+      for (i=0;i<N;i++)
+      {
+         spx_word32_t MM;
+         spx_word32_t theta;
+         spx_word16_t prior_ratio;
+         spx_word16_t tmp;
+         spx_word16_t p;
+         spx_word16_t g;
+         
+         /* Wiener filter gain */
+         prior_ratio = PDIV32_16(SHL32(EXTEND32(st->prior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT)));
+         theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT));
+
+         /* Optimal estimator for loudness domain */
+         MM = hypergeom_gain(theta);
+         /* EM gain with bound */
+         g = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM)));
+         /* Interpolated speech probability of presence */
+         p = st->gain2[i];
+                  
+         /* Constrain the gain to be close to the Bark scale gain */
+         if (MULT16_16_Q15(QCONST16(.333f,15),g) > st->gain[i])
+            g = MULT16_16(3,st->gain[i]);
+         st->gain[i] = g;
+         
+         /* Save old power spectrum */
+         st->old_ps[i] = MULT16_32_P15(QCONST16(.2f,15),st->old_ps[i]) + MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(st->gain[i])),ps[i]);
+         
+         /* Apply gain floor */
+         if (st->gain[i] < st->gain_floor[i])
+            st->gain[i] = st->gain_floor[i];
+
+         /* Exponential decay model for reverberation (unused) */
+         /*st->reverb_estimate[i] = st->reverb_decay*st->reverb_estimate[i] + st->reverb_decay*st->reverb_level*st->gain[i]*st->gain[i]*st->ps[i];*/
+         
+         /* Take into account speech probability of presence (loudness domain MMSE estimator) */
+         /* gain2 = [p*sqrt(gain)+(1-p)*sqrt(gain _floor) ]^2 */
+         tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15)));
+         st->gain2[i]=SQR16_Q15(tmp);
+
+         /* Use this if you want a log-domain MMSE estimator instead */
+         /*st->gain2[i] = pow(st->gain[i], p) * pow(st->gain_floor[i],1.f-p);*/
+      }
+   } else {
+      for (i=N;i<N+M;i++)
+      {
+         spx_word16_t tmp;
+         spx_word16_t p = st->gain2[i];
+         st->gain[i] = MAX16(st->gain[i], st->gain_floor[i]);         
+         tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15)));
+         st->gain2[i]=SQR16_Q15(tmp);
+      }
+      filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2);
+   }
+   
+   /* If noise suppression is off, don't apply the gain (but then why call this in the first place!) */
+   if (!st->denoise_enabled)
+   {
+      for (i=0;i<N+M;i++)
+         st->gain2[i]=Q15_ONE;
+   }
+      
+   /* Apply computed gain */
+   for (i=1;i<N;i++)
+   {
+      st->ft[2*i-1] = MULT16_16_P15(st->gain2[i],st->ft[2*i-1]);
+      st->ft[2*i] = MULT16_16_P15(st->gain2[i],st->ft[2*i]);
+   }
+   st->ft[0] = MULT16_16_P15(st->gain2[0],st->ft[0]);
+   st->ft[2*N-1] = MULT16_16_P15(st->gain2[N-1],st->ft[2*N-1]);
+   
+   /*FIXME: This *will* not work for fixed-point */
+#ifndef FIXED_POINT
+   if (st->agc_enabled)
+      speex_compute_agc(st, Pframe, st->ft);
+#endif
+
+   /* Inverse FFT with 1/N scaling */
+   spx_ifft(st->fft_lookup, st->ft, st->frame);
+   /* Scale back to original (lower) amplitude */
+   for (i=0;i<2*N;i++)
+      st->frame[i] = PSHR16(st->frame[i], st->frame_shift);
+
+   /*FIXME: This *will* not work for fixed-point */
+#ifndef FIXED_POINT
+   if (st->agc_enabled)
+   {
+      float max_sample=0;
+      for (i=0;i<2*N;i++)
+         if (fabs(st->frame[i])>max_sample)
+            max_sample = fabs(st->frame[i]);
+      if (max_sample>28000.f)
+      {
+         float damp = 28000.f/max_sample;
+         for (i=0;i<2*N;i++)
+            st->frame[i] *= damp;
+      }
+   }
+#endif
+   
+   /* Synthesis window (for WOLA) */
+   for (i=0;i<2*N;i++)
+      st->frame[i] = MULT16_16_Q15(st->frame[i], st->window[i]);
+
+   /* Perform overlap and add */
+   for (i=0;i<N3;i++)
+      x[i] = st->outbuf[i] + st->frame[i];
+   for (i=0;i<N4;i++)
+      x[N3+i] = st->frame[N3+i];
+   
+   /* Update outbuf */
+   for (i=0;i<N3;i++)
+      st->outbuf[i] = st->frame[st->frame_size+i];
+
+   /* FIXME: This VAD is a kludge */
+   if (st->vad_enabled)
+   {
+      if (Pframe > st->speech_prob_start || (st->was_speech && Pframe > st->speech_prob_continue))
+      {
+         st->was_speech=1;
+         return 1;
+      } else
+      {
+         st->was_speech=0;
+         return 0;
+      }
+   } else {
+      return 1;
+   }
+}
+
+void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x)
+{
+   int i;
+   int N = st->ps_size;
+   int N3 = 2*N - st->frame_size;
+   int M;
+   spx_word32_t *ps=st->ps;
+
+   M = st->nbands;
+   st->min_count++;
+   
+   preprocess_analysis(st, x);
+
+   update_noise_prob(st);
+   
+   for (i=1;i<N-1;i++)
+   {
+      if (!st->update_prob[i] || st->ps[i] < PSHR32(st->noise[i],NOISE_SHIFT))
+      {
+         st->noise[i] = MULT16_32_Q15(QCONST16(.95f,15),st->noise[i]) + MULT16_32_Q15(QCONST16(.05f,15),SHL32(st->ps[i],NOISE_SHIFT));
+      }
+   }
+
+   for (i=0;i<N3;i++)
+      st->outbuf[i] = MULT16_16_Q15(x[st->frame_size-N3+i],st->window[st->frame_size+i]);
+
+   /* Save old power spectrum */
+   for (i=0;i<N+M;i++)
+      st->old_ps[i] = ps[i];
+
+   for (i=0;i<N;i++)
+      st->reverb_estimate[i] = MULT16_32_Q15(st->reverb_decay, st->reverb_estimate[i]);
+}
+
+
+int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr)
+{
+   int i;
+   SpeexPreprocessState *st;
+   st=(SpeexPreprocessState*)state;
+   switch(request)
+   {
+   case SPEEX_PREPROCESS_SET_DENOISE:
+      st->denoise_enabled = (*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_PREPROCESS_GET_DENOISE:
+      (*(spx_int32_t*)ptr) = st->denoise_enabled;
+      break;
+#ifndef FIXED_POINT
+   case SPEEX_PREPROCESS_SET_AGC:
+      st->agc_enabled = (*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_PREPROCESS_GET_AGC:
+      (*(spx_int32_t*)ptr) = st->agc_enabled;
+      break;
+
+   case SPEEX_PREPROCESS_SET_AGC_LEVEL:
+      st->agc_level = (*(float*)ptr);
+      if (st->agc_level<1)
+         st->agc_level=1;
+      if (st->agc_level>32768)
+         st->agc_level=32768;
+      break;
+   case SPEEX_PREPROCESS_GET_AGC_LEVEL:
+      (*(float*)ptr) = st->agc_level;
+      break;
+   case SPEEX_PREPROCESS_SET_AGC_INCREMENT:
+      st->max_increase_step = exp(0.11513f * (*(spx_int32_t*)ptr)*st->frame_size / st->sampling_rate);
+      break;
+   case SPEEX_PREPROCESS_GET_AGC_INCREMENT:
+      (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->max_increase_step)*st->sampling_rate/st->frame_size);
+      break;
+   case SPEEX_PREPROCESS_SET_AGC_DECREMENT:
+      st->max_decrease_step = exp(0.11513f * (*(spx_int32_t*)ptr)*st->frame_size / st->sampling_rate);
+      break;
+   case SPEEX_PREPROCESS_GET_AGC_DECREMENT:
+      (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->max_decrease_step)*st->sampling_rate/st->frame_size);
+      break;
+   case SPEEX_PREPROCESS_SET_AGC_MAX_GAIN:
+      st->max_gain = exp(0.11513f * (*(spx_int32_t*)ptr));
+      break;
+   case SPEEX_PREPROCESS_GET_AGC_MAX_GAIN:
+      (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->max_gain));
+      break;
+#endif
+   case SPEEX_PREPROCESS_SET_VAD:
+      speex_warning("The VAD has been replaced by a hack pending a complete rewrite");
+      st->vad_enabled = (*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_PREPROCESS_GET_VAD:
+      (*(spx_int32_t*)ptr) = st->vad_enabled;
+      break;
+   
+   case SPEEX_PREPROCESS_SET_DEREVERB:
+      st->dereverb_enabled = (*(spx_int32_t*)ptr);
+      for (i=0;i<st->ps_size;i++)
+         st->reverb_estimate[i]=0;
+      break;
+   case SPEEX_PREPROCESS_GET_DEREVERB:
+      (*(spx_int32_t*)ptr) = st->dereverb_enabled;
+      break;
+
+   case SPEEX_PREPROCESS_SET_DEREVERB_LEVEL:
+      st->reverb_level = (*(float*)ptr);
+      break;
+   case SPEEX_PREPROCESS_GET_DEREVERB_LEVEL:
+      (*(float*)ptr) = st->reverb_level;
+      break;
+   
+   case SPEEX_PREPROCESS_SET_DEREVERB_DECAY:
+      st->reverb_decay = (*(float*)ptr);
+      break;
+   case SPEEX_PREPROCESS_GET_DEREVERB_DECAY:
+      (*(float*)ptr) = st->reverb_decay;
+      break;
+
+   case SPEEX_PREPROCESS_SET_PROB_START:
+      *(spx_int32_t*)ptr = MIN32(Q15_ONE,MAX32(0, *(spx_int32_t*)ptr));
+      st->speech_prob_start = DIV32_16(MULT16_16(32767,*(spx_int32_t*)ptr), 100);
+      break;
+   case SPEEX_PREPROCESS_GET_PROB_START:
+      (*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob_start, 100);
+      break;
+
+   case SPEEX_PREPROCESS_SET_PROB_CONTINUE:
+      *(spx_int32_t*)ptr = MIN32(Q15_ONE,MAX32(0, *(spx_int32_t*)ptr));
+      st->speech_prob_continue = DIV32_16(MULT16_16(32767,*(spx_int32_t*)ptr), 100);
+      break;
+   case SPEEX_PREPROCESS_GET_PROB_CONTINUE:
+      (*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob_continue, 100);
+      break;
+
+   case SPEEX_PREPROCESS_SET_NOISE_SUPPRESS:
+      st->noise_suppress = -ABS(*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_PREPROCESS_GET_NOISE_SUPPRESS:
+      (*(spx_int32_t*)ptr) = st->noise_suppress;
+      break;
+   case SPEEX_PREPROCESS_SET_ECHO_SUPPRESS:
+      st->echo_suppress = -ABS(*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_PREPROCESS_GET_ECHO_SUPPRESS:
+      (*(spx_int32_t*)ptr) = st->echo_suppress;
+      break;
+   case SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE:
+      st->echo_suppress_active = -ABS(*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE:
+      (*(spx_int32_t*)ptr) = st->echo_suppress_active;
+      break;
+   case SPEEX_PREPROCESS_SET_ECHO_STATE:
+      st->echo_state = (SpeexEchoState*)ptr;
+      break;
+   case SPEEX_PREPROCESS_GET_ECHO_STATE:
+      ptr = (void*)st->echo_state;
+      break;
+
+   default:
+      speex_warning_int("Unknown speex_preprocess_ctl request: ", request);
+      return -1;
+   }
+   return 0;
+}
diff --git a/3rdparty/speex/libspeex/pseudofloat.h b/3rdparty/speex/libspeex/pseudofloat.h
new file mode 100644
index 0000000..a6c4762
--- /dev/null
+++ b/3rdparty/speex/libspeex/pseudofloat.h
@@ -0,0 +1,378 @@
+/* Copyright (C) 2005 Jean-Marc Valin */
+/**
+   @file pseudofloat.h
+   @brief Pseudo-floating point
+ * This header file provides a lightweight floating point type for
+ * use on fixed-point platforms when a large dynamic range is 
+ * required. The new type is not compatible with the 32-bit IEEE format,
+ * it is not even remotely as accurate as 32-bit floats, and is not
+ * even guaranteed to produce even remotely correct results for code
+ * other than Speex. It makes all kinds of shortcuts that are acceptable
+ * for Speex, but may not be acceptable for your application. You're
+ * quite welcome to reuse this code and improve it, but don't assume
+ * it works out of the box. Most likely, it doesn't.
+ */
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef PSEUDOFLOAT_H
+#define PSEUDOFLOAT_H
+
+#include "misc.h"
+#include "math_approx.h"
+#include <math.h>
+
+#ifdef FIXED_POINT
+
+typedef struct {
+   spx_int16_t m;
+   spx_int16_t e;
+} spx_float_t;
+
+static const spx_float_t FLOAT_ZERO = {0,0};
+static const spx_float_t FLOAT_ONE = {16384,-14};
+static const spx_float_t FLOAT_HALF = {16384,-15};
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+static inline spx_float_t PSEUDOFLOAT(spx_int32_t x)
+{
+   int e=0;
+   int sign=0;
+   if (x<0)
+   {
+      sign = 1;
+      x = -x;
+   }
+   if (x==0)
+   {
+      spx_float_t r = {0,0};
+      return r;
+   }
+   e = spx_ilog2(ABS32(x))-14;
+   x = VSHR32(x, e);
+   if (sign)
+   {
+      spx_float_t r;
+      r.m = -x;
+      r.e = e;
+      return r;
+   }
+   else      
+   {
+      spx_float_t r;
+      r.m = x;
+      r.e = e;
+      return r;
+   }
+}
+
+
+static inline spx_float_t FLOAT_ADD(spx_float_t a, spx_float_t b)
+{
+   spx_float_t r;
+   if (a.m==0)
+      return b;
+   else if (b.m==0)
+      return a;
+   if ((a).e > (b).e) 
+   {
+      r.m = ((a).m>>1) + ((b).m>>MIN(15,(a).e-(b).e+1));
+      r.e = (a).e+1;
+   }
+   else 
+   {
+      r.m = ((b).m>>1) + ((a).m>>MIN(15,(b).e-(a).e+1));
+      r.e = (b).e+1;
+   }
+   if (r.m>0)
+   {
+      if (r.m<16384)
+      {
+         r.m<<=1;
+         r.e-=1;
+      }
+   } else {
+      if (r.m>-16384)
+      {
+         r.m<<=1;
+         r.e-=1;
+      }
+   }
+   /*printf ("%f + %f = %f\n", REALFLOAT(a), REALFLOAT(b), REALFLOAT(r));*/
+   return r;
+}
+
+static inline spx_float_t FLOAT_SUB(spx_float_t a, spx_float_t b)
+{
+   spx_float_t r;
+   if (a.m==0)
+      return b;
+   else if (b.m==0)
+      return a;
+   if ((a).e > (b).e)
+   {
+      r.m = ((a).m>>1) - ((b).m>>MIN(15,(a).e-(b).e+1));
+      r.e = (a).e+1;
+   }
+   else 
+   {
+      r.m = ((a).m>>MIN(15,(b).e-(a).e+1)) - ((b).m>>1);
+      r.e = (b).e+1;
+   }
+   if (r.m>0)
+   {
+      if (r.m<16384)
+      {
+         r.m<<=1;
+         r.e-=1;
+      }
+   } else {
+      if (r.m>-16384)
+      {
+         r.m<<=1;
+         r.e-=1;
+      }
+   }
+   /*printf ("%f + %f = %f\n", REALFLOAT(a), REALFLOAT(b), REALFLOAT(r));*/
+   return r;
+}
+
+static inline int FLOAT_LT(spx_float_t a, spx_float_t b)
+{
+   if (a.m==0)
+      return b.m>0;
+   else if (b.m==0)
+      return a.m<0;   
+   if ((a).e > (b).e)
+      return ((a).m>>1) < ((b).m>>MIN(15,(a).e-(b).e+1));
+   else 
+      return ((b).m>>1) > ((a).m>>MIN(15,(b).e-(a).e+1));
+
+}
+
+static inline int FLOAT_GT(spx_float_t a, spx_float_t b)
+{
+   return FLOAT_LT(b,a);
+}
+
+static inline spx_float_t FLOAT_MULT(spx_float_t a, spx_float_t b)
+{
+   spx_float_t r;
+   r.m = (spx_int16_t)((spx_int32_t)(a).m*(b).m>>15);
+   r.e = (a).e+(b).e+15;
+   if (r.m>0)
+   {
+      if (r.m<16384)
+      {
+         r.m<<=1;
+         r.e-=1;
+      }
+   } else {
+      if (r.m>-16384)
+      {
+         r.m<<=1;
+         r.e-=1;
+      }
+   }
+   /*printf ("%f * %f = %f\n", REALFLOAT(a), REALFLOAT(b), REALFLOAT(r));*/
+   return r;   
+}
+
+static inline spx_float_t FLOAT_AMULT(spx_float_t a, spx_float_t b)
+{
+   spx_float_t r;
+   r.m = (spx_int16_t)((spx_int32_t)(a).m*(b).m>>15);
+   r.e = (a).e+(b).e+15;
+   return r;   
+}
+
+
+static inline spx_float_t FLOAT_SHL(spx_float_t a, int b)
+{
+   spx_float_t r;
+   r.m = a.m;
+   r.e = a.e+b;
+   return r;
+}
+
+static inline spx_int16_t FLOAT_EXTRACT16(spx_float_t a)
+{
+   if (a.e<0)
+      return EXTRACT16((EXTEND32(a.m)+(EXTEND32(1)<<(-a.e-1)))>>-a.e);
+   else
+      return a.m<<a.e;
+}
+
+static inline spx_int32_t FLOAT_EXTRACT32(spx_float_t a)
+{
+   if (a.e<0)
+      return (EXTEND32(a.m)+(EXTEND32(1)<<(-a.e-1)))>>-a.e;
+   else
+      return EXTEND32(a.m)<<a.e;
+}
+
+static inline spx_int32_t FLOAT_MUL32(spx_float_t a, spx_word32_t b)
+{
+   return VSHR32(MULT16_32_Q15(a.m, b),-a.e-15);
+}
+
+static inline spx_float_t FLOAT_MUL32U(spx_word32_t a, spx_word32_t b)
+{
+   int e1, e2;
+   spx_float_t r;
+   if (a==0 || b==0)
+   {
+      return FLOAT_ZERO;
+   }
+   e1 = spx_ilog2(ABS32(a));
+   a = VSHR32(a, e1-14);
+   e2 = spx_ilog2(ABS32(b));
+   b = VSHR32(b, e2-14);
+   r.m = MULT16_16_Q15(a,b);
+   r.e = e1+e2-13;
+   return r;
+}
+
+/* Do NOT attempt to divide by a negative number */
+static inline spx_float_t FLOAT_DIV32_FLOAT(spx_word32_t a, spx_float_t b)
+{
+   int e=0;
+   spx_float_t r;
+   if (a==0)
+   {
+      return FLOAT_ZERO;
+   }
+   e = spx_ilog2(ABS32(a))-spx_ilog2(b.m-1)-15;
+   a = VSHR32(a, e);
+   if (ABS32(a)>=SHL32(EXTEND32(b.m-1),15))
+   {
+      a >>= 1;
+      e++;
+   }
+   r.m = DIV32_16(a,b.m);
+   r.e = e-b.e;
+   return r;
+}
+
+
+/* Do NOT attempt to divide by a negative number */
+static inline spx_float_t FLOAT_DIV32(spx_word32_t a, spx_word32_t b)
+{
+   int e0=0,e=0;
+   spx_float_t r;
+   if (a==0)
+   {
+      return FLOAT_ZERO;
+   }
+   if (b>32767)
+   {
+      e0 = spx_ilog2(b)-14;
+      b = VSHR32(b, e0);
+      e0 = -e0;
+   }
+   e = spx_ilog2(ABS32(a))-spx_ilog2(b-1)-15;
+   a = VSHR32(a, e);
+   if (ABS32(a)>=SHL32(EXTEND32(b-1),15))
+   {
+      a >>= 1;
+      e++;
+   }
+   e += e0;
+   r.m = DIV32_16(a,b);
+   r.e = e;
+   return r;
+}
+
+/* Do NOT attempt to divide by a negative number */
+static inline spx_float_t FLOAT_DIVU(spx_float_t a, spx_float_t b)
+{
+   int e=0;
+   spx_int32_t num;
+   spx_float_t r;
+   if (b.m<=0)
+   {
+      speex_warning_int("Attempted to divide by", b.m);
+      return FLOAT_ONE;
+   }
+   num = a.m;
+   a.m = ABS16(a.m);
+   while (a.m >= b.m)
+   {
+      e++;
+      a.m >>= 1;
+   }
+   num = num << (15-e);
+   r.m = DIV32_16(num,b.m);
+   r.e = a.e-b.e-15+e;
+   return r;
+}
+
+static inline spx_float_t FLOAT_SQRT(spx_float_t a)
+{
+   spx_float_t r;
+   spx_int32_t m;
+   m = SHL32(EXTEND32(a.m), 14);
+   r.e = a.e - 14;
+   if (r.e & 1)
+   {
+      r.e -= 1;
+      m <<= 1;
+   }
+   r.e >>= 1;
+   r.m = spx_sqrt(m);
+   return r;
+}
+
+#else
+
+#define spx_float_t float
+#define FLOAT_ZERO 0.f
+#define FLOAT_ONE 1.f
+#define FLOAT_HALF 0.5f
+#define PSEUDOFLOAT(x) (x)
+#define FLOAT_MULT(a,b) ((a)*(b))
+#define FLOAT_AMULT(a,b) ((a)*(b))
+#define FLOAT_MUL32(a,b) ((a)*(b))
+#define FLOAT_DIV32(a,b) ((a)/(b))
+#define FLOAT_EXTRACT16(a) (a)
+#define FLOAT_EXTRACT32(a) (a)
+#define FLOAT_ADD(a,b) ((a)+(b))
+#define FLOAT_SUB(a,b) ((a)-(b))
+#define REALFLOAT(x) (x)
+#define FLOAT_DIV32_FLOAT(a,b) ((a)/(b))
+#define FLOAT_MUL32U(a,b) ((a)*(b))
+#define FLOAT_SHL(a,b) (a)
+#define FLOAT_LT(a,b) ((a)<(b))
+#define FLOAT_GT(a,b) ((a)>(b))
+#define FLOAT_DIVU(a,b) ((a)/(b))
+#define FLOAT_SQRT(a) (spx_sqrt(a))
+
+#endif
+
+#endif
diff --git a/3rdparty/speex/libspeex/quant_lsp.c b/3rdparty/speex/libspeex/quant_lsp.c
new file mode 100644
index 0000000..d907b98
--- /dev/null
+++ b/3rdparty/speex/libspeex/quant_lsp.c
@@ -0,0 +1,447 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: quant_lsp.c
+   LSP vector quantization
+
+   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 "quant_lsp.h"
+#include <math.h>
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#include "misc.h"
+
+#ifdef BFIN_ASM
+#include "quant_lsp_bfin.h"
+#endif
+
+#ifdef FIXED_POINT
+
+#define LSP_LINEAR(i) (SHL16(i+1,11))
+#define LSP_LINEAR_HIGH(i) (ADD16(MULT16_16_16(i,2560),6144))
+#define LSP_DIV_256(x) (SHL16((spx_word16_t)x, 5))
+#define LSP_DIV_512(x) (SHL16((spx_word16_t)x, 4))
+#define LSP_DIV_1024(x) (SHL16((spx_word16_t)x, 3))
+#define LSP_PI 25736
+
+#else
+
+#define LSP_LINEAR(i) (.25*(i)+.25)
+#define LSP_LINEAR_HIGH(i) (.3125*(i)+.75)
+#define LSP_SCALE 256.
+#define LSP_DIV_256(x) (0.0039062*(x))
+#define LSP_DIV_512(x) (0.0019531*(x))
+#define LSP_DIV_1024(x) (0.00097656*(x))
+#define LSP_PI M_PI
+
+#endif
+
+static void compute_quant_weights(spx_lsp_t *qlsp, spx_word16_t *quant_weight, int order)
+{
+   int i;
+   spx_word16_t tmp1, tmp2;
+   for (i=0;i<order;i++)
+   {
+      if (i==0)
+         tmp1 = qlsp[i];
+      else
+         tmp1 = qlsp[i]-qlsp[i-1];
+      if (i==order-1)
+         tmp2 = LSP_PI-qlsp[i];
+      else
+         tmp2 = qlsp[i+1]-qlsp[i];
+      if (tmp2<tmp1)
+         tmp1 = tmp2;
+#ifdef FIXED_POINT
+      quant_weight[i] = DIV32_16(81920,ADD16(300,tmp1));
+#else
+      quant_weight[i] = 10/(.04+tmp1);
+#endif
+   }
+
+}
+
+/* Note: x is modified*/
+#ifndef OVERRIDE_LSP_QUANT
+static int lsp_quant(spx_word16_t *x, const signed char *cdbk, int nbVec, int nbDim)
+{
+   int i,j;
+   spx_word32_t dist;
+   spx_word16_t tmp;
+   spx_word32_t best_dist=VERY_LARGE32;
+   int best_id=0;
+   const signed char *ptr=cdbk;
+   for (i=0;i<nbVec;i++)
+   {
+      dist=0;
+      for (j=0;j<nbDim;j++)
+      {
+         tmp=SUB16(x[j],SHL16((spx_word16_t)*ptr++,5));
+         dist=MAC16_16(dist,tmp,tmp);
+      } 
+      if (dist<best_dist)
+      {
+         best_dist=dist;
+         best_id=i;
+      }
+   }
+
+   for (j=0;j<nbDim;j++)
+      x[j] = SUB16(x[j],SHL16((spx_word16_t)cdbk[best_id*nbDim+j],5));
+    
+   return best_id;
+}
+#endif
+
+/* Note: x is modified*/
+#ifndef OVERRIDE_LSP_WEIGHT_QUANT
+static int lsp_weight_quant(spx_word16_t *x, spx_word16_t *weight, const signed char *cdbk, int nbVec, int nbDim)
+{
+   int i,j;
+   spx_word32_t dist;
+   spx_word16_t tmp;
+   spx_word32_t best_dist=VERY_LARGE32;
+   int best_id=0;
+   const signed char *ptr=cdbk;
+   for (i=0;i<nbVec;i++)
+   {
+      dist=0;
+      for (j=0;j<nbDim;j++)
+      {
+         tmp=SUB16(x[j],SHL16((spx_word16_t)*ptr++,5));
+         dist=MAC16_32_Q15(dist,weight[j],MULT16_16(tmp,tmp));
+      }
+      if (dist<best_dist)
+      {
+         best_dist=dist;
+         best_id=i;
+      }
+   }
+   
+   for (j=0;j<nbDim;j++)
+      x[j] = SUB16(x[j],SHL16((spx_word16_t)cdbk[best_id*nbDim+j],5));
+   return best_id;
+}
+#endif
+
+void lsp_quant_nb(spx_lsp_t *lsp, spx_lsp_t *qlsp, int order, SpeexBits *bits)
+{
+   int i;
+   int id;
+   spx_word16_t quant_weight[10];
+   
+   for (i=0;i<order;i++)
+      qlsp[i]=lsp[i];
+
+   compute_quant_weights(qlsp, quant_weight, order);
+
+   for (i=0;i<order;i++)
+      qlsp[i]=SUB16(qlsp[i],LSP_LINEAR(i));
+
+#ifndef FIXED_POINT
+   for (i=0;i<order;i++)
+      qlsp[i] = LSP_SCALE*qlsp[i];
+#endif
+   id = lsp_quant(qlsp, cdbk_nb, NB_CDBK_SIZE, order);
+   speex_bits_pack(bits, id, 6);
+
+   for (i=0;i<order;i++)
+      qlsp[i]*=2;
+ 
+   id = lsp_weight_quant(qlsp, quant_weight, cdbk_nb_low1, NB_CDBK_SIZE_LOW1, 5);
+   speex_bits_pack(bits, id, 6);
+
+   for (i=0;i<5;i++)
+      qlsp[i]*=2;
+
+   id = lsp_weight_quant(qlsp, quant_weight, cdbk_nb_low2, NB_CDBK_SIZE_LOW2, 5);
+   speex_bits_pack(bits, id, 6);
+
+   id = lsp_weight_quant(qlsp+5, quant_weight+5, cdbk_nb_high1, NB_CDBK_SIZE_HIGH1, 5);
+   speex_bits_pack(bits, id, 6);
+
+   for (i=5;i<10;i++)
+      qlsp[i]*=2;
+
+   id = lsp_weight_quant(qlsp+5, quant_weight+5, cdbk_nb_high2, NB_CDBK_SIZE_HIGH2, 5);
+   speex_bits_pack(bits, id, 6);
+
+#ifdef FIXED_POINT
+   for (i=0;i<order;i++)
+      qlsp[i]=PSHR16(qlsp[i],2);
+#else
+   for (i=0;i<order;i++)
+      qlsp[i]=qlsp[i] * .00097656;
+#endif
+
+   for (i=0;i<order;i++)
+      qlsp[i]=lsp[i]-qlsp[i];
+}
+
+void lsp_unquant_nb(spx_lsp_t *lsp, int order, SpeexBits *bits)
+{
+   int i, id;
+   for (i=0;i<order;i++)
+      lsp[i]=LSP_LINEAR(i);
+
+
+   id=speex_bits_unpack_unsigned(bits, 6);
+   for (i=0;i<10;i++)
+      lsp[i] = ADD32(lsp[i], LSP_DIV_256(cdbk_nb[id*10+i]));
+
+   id=speex_bits_unpack_unsigned(bits, 6);
+   for (i=0;i<5;i++)
+      lsp[i] = ADD16(lsp[i], LSP_DIV_512(cdbk_nb_low1[id*5+i]));
+
+   id=speex_bits_unpack_unsigned(bits, 6);
+   for (i=0;i<5;i++)
+      lsp[i] = ADD32(lsp[i], LSP_DIV_1024(cdbk_nb_low2[id*5+i]));
+
+   id=speex_bits_unpack_unsigned(bits, 6);
+   for (i=0;i<5;i++)
+      lsp[i+5] = ADD32(lsp[i+5], LSP_DIV_512(cdbk_nb_high1[id*5+i]));
+   
+   id=speex_bits_unpack_unsigned(bits, 6);
+   for (i=0;i<5;i++)
+      lsp[i+5] = ADD32(lsp[i+5], LSP_DIV_1024(cdbk_nb_high2[id*5+i]));
+}
+
+
+void lsp_quant_lbr(spx_lsp_t *lsp, spx_lsp_t *qlsp, int order, SpeexBits *bits)
+{
+   int i;
+   int id;
+   spx_word16_t quant_weight[10];
+
+   for (i=0;i<order;i++)
+      qlsp[i]=lsp[i];
+
+   compute_quant_weights(qlsp, quant_weight, order);
+
+   for (i=0;i<order;i++)
+      qlsp[i]=SUB16(qlsp[i],LSP_LINEAR(i));
+#ifndef FIXED_POINT
+   for (i=0;i<order;i++)
+      qlsp[i]=qlsp[i]*LSP_SCALE;
+#endif
+   id = lsp_quant(qlsp, cdbk_nb, NB_CDBK_SIZE, order);
+   speex_bits_pack(bits, id, 6);
+   
+   for (i=0;i<order;i++)
+      qlsp[i]*=2;
+   
+   id = lsp_weight_quant(qlsp, quant_weight, cdbk_nb_low1, NB_CDBK_SIZE_LOW1, 5);
+   speex_bits_pack(bits, id, 6);
+
+   id = lsp_weight_quant(qlsp+5, quant_weight+5, cdbk_nb_high1, NB_CDBK_SIZE_HIGH1, 5);
+   speex_bits_pack(bits, id, 6);
+
+#ifdef FIXED_POINT
+   for (i=0;i<order;i++)
+      qlsp[i] = PSHR16(qlsp[i],1);
+#else
+   for (i=0;i<order;i++)
+      qlsp[i] = qlsp[i]*0.0019531;
+#endif
+
+   for (i=0;i<order;i++)
+      qlsp[i]=lsp[i]-qlsp[i];
+}
+
+void lsp_unquant_lbr(spx_lsp_t *lsp, int order, SpeexBits *bits)
+{
+   int i, id;
+   for (i=0;i<order;i++)
+      lsp[i]=LSP_LINEAR(i);
+
+
+   id=speex_bits_unpack_unsigned(bits, 6);
+   for (i=0;i<10;i++)
+      lsp[i] += LSP_DIV_256(cdbk_nb[id*10+i]);
+
+   id=speex_bits_unpack_unsigned(bits, 6);
+   for (i=0;i<5;i++)
+      lsp[i] += LSP_DIV_512(cdbk_nb_low1[id*5+i]);
+
+   id=speex_bits_unpack_unsigned(bits, 6);
+   for (i=0;i<5;i++)
+      lsp[i+5] += LSP_DIV_512(cdbk_nb_high1[id*5+i]);
+   
+}
+
+
+#ifdef DISABLE_WIDEBAND
+void lsp_quant_high(spx_lsp_t *lsp, spx_lsp_t *qlsp, int order, SpeexBits *bits)
+{
+   speex_error("Wideband and Ultra-wideband are disabled");
+}
+void lsp_unquant_high(spx_lsp_t *lsp, int order, SpeexBits *bits)
+{
+   speex_error("Wideband and Ultra-wideband are disabled");
+}
+#else
+extern const signed char high_lsp_cdbk[];
+extern const signed char high_lsp_cdbk2[];
+
+
+void lsp_quant_high(spx_lsp_t *lsp, spx_lsp_t *qlsp, int order, SpeexBits *bits)
+{
+   int i;
+   int id;
+   spx_word16_t quant_weight[10];
+
+   for (i=0;i<order;i++)
+      qlsp[i]=lsp[i];
+
+   compute_quant_weights(qlsp, quant_weight, order);
+
+   /*   quant_weight[0] = 10/(qlsp[1]-qlsp[0]);
+   quant_weight[order-1] = 10/(qlsp[order-1]-qlsp[order-2]);
+   for (i=1;i<order-1;i++)
+   {
+      tmp1 = 10/(qlsp[i]-qlsp[i-1]);
+      tmp2 = 10/(qlsp[i+1]-qlsp[i]);
+      quant_weight[i] = tmp1 > tmp2 ? tmp1 : tmp2;
+      }*/
+
+   for (i=0;i<order;i++)
+      qlsp[i]=SUB16(qlsp[i],LSP_LINEAR_HIGH(i));
+#ifndef FIXED_POINT
+   for (i=0;i<order;i++)
+      qlsp[i] = qlsp[i]*LSP_SCALE;
+#endif
+   id = lsp_quant(qlsp, high_lsp_cdbk, 64, order);
+   speex_bits_pack(bits, id, 6);
+
+   for (i=0;i<order;i++)
+      qlsp[i]*=2;
+
+   id = lsp_weight_quant(qlsp, quant_weight, high_lsp_cdbk2, 64, order);
+   speex_bits_pack(bits, id, 6);
+
+#ifdef FIXED_POINT
+   for (i=0;i<order;i++)
+      qlsp[i] = PSHR16(qlsp[i],1);
+#else
+   for (i=0;i<order;i++)
+      qlsp[i] = qlsp[i]*0.0019531;
+#endif
+
+   for (i=0;i<order;i++)
+      qlsp[i]=lsp[i]-qlsp[i];
+}
+
+void lsp_unquant_high(spx_lsp_t *lsp, int order, SpeexBits *bits)
+{
+
+   int i, id;
+   for (i=0;i<order;i++)
+      lsp[i]=LSP_LINEAR_HIGH(i);
+
+
+   id=speex_bits_unpack_unsigned(bits, 6);
+   for (i=0;i<order;i++)
+      lsp[i] += LSP_DIV_256(high_lsp_cdbk[id*order+i]);
+
+
+   id=speex_bits_unpack_unsigned(bits, 6);
+   for (i=0;i<order;i++)
+      lsp[i] += LSP_DIV_512(high_lsp_cdbk2[id*order+i]);
+}
+
+#endif
+
+
+#ifdef EPIC_48K
+
+extern const signed char cdbk_lsp_vlbr[5120];
+extern const signed char cdbk_lsp2_vlbr[160];
+
+void lsp_quant_48k(spx_lsp_t *lsp, spx_lsp_t *qlsp, int order, SpeexBits *bits)
+{
+   int i;
+   int id;
+   spx_word16_t quant_weight[10];
+
+   for (i=0;i<order;i++)
+      qlsp[i]=lsp[i];
+
+   compute_quant_weights(qlsp, quant_weight, order);
+
+   for (i=0;i<order;i++)
+      qlsp[i]=SUB16(qlsp[i],LSP_SCALING*(.25*i+.3125));
+#ifndef FIXED_POINT
+   for (i=0;i<order;i++)
+      qlsp[i] = qlsp[i]*LSP_SCALE;
+#endif
+   
+   id = lsp_quant(qlsp, cdbk_lsp_vlbr, 512, order);
+   speex_bits_pack(bits, id, 9);
+
+   for (i=0;i<order;i++)
+      qlsp[i]*=4;
+   
+   id = lsp_weight_quant(qlsp, quant_weight, cdbk_lsp2_vlbr, 16, 10);
+   speex_bits_pack(bits, id, 4);
+
+#ifdef FIXED_POINT
+   for (i=0;i<order;i++)
+      qlsp[i]=PSHR16(qlsp[i],2);
+#else
+   for (i=0;i<order;i++)
+      qlsp[i]=qlsp[i]*0.00097655;
+#endif
+
+   for (i=0;i<order;i++)
+      qlsp[i]=lsp[i]-qlsp[i];
+}
+
+void lsp_unquant_48k(spx_lsp_t *lsp, int order, SpeexBits *bits)
+{
+   int i, id;
+   for (i=0;i<order;i++)
+      lsp[i]=LSP_SCALING*(.25*i+.3125);
+
+
+   id=speex_bits_unpack_unsigned(bits, 9);
+   for (i=0;i<10;i++)
+      lsp[i] += LSP_SCALING*0.0039062*cdbk_lsp_vlbr[id*10+i];
+
+   id=speex_bits_unpack_unsigned(bits, 4);
+   for (i=0;i<10;i++)
+      lsp[i] += LSP_SCALING*0.00097655*cdbk_lsp2_vlbr[id*10+i];
+   
+}
+
+#endif
diff --git a/3rdparty/speex/libspeex/quant_lsp.h b/3rdparty/speex/libspeex/quant_lsp.h
new file mode 100644
index 0000000..c6d5bb3
--- /dev/null
+++ b/3rdparty/speex/libspeex/quant_lsp.h
@@ -0,0 +1,83 @@
+/* Copyright (C) 2002 Jean-Marc Valin */
+/**
+   @file quant_lsp.h
+   @brief LSP vector quantization
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef QUANT_LSP_H
+#define QUANT_LSP_H
+
+#include <speex/speex_bits.h>
+#include "misc.h"
+
+#define MAX_LSP_SIZE 20
+
+#define NB_CDBK_SIZE 64
+#define NB_CDBK_SIZE_LOW1 64
+#define NB_CDBK_SIZE_LOW2 64
+#define NB_CDBK_SIZE_HIGH1 64
+#define NB_CDBK_SIZE_HIGH2 64
+
+/*Narrowband codebooks*/
+extern const signed char cdbk_nb[];
+extern const signed char cdbk_nb_low1[];
+extern const signed char cdbk_nb_low2[];
+extern const signed char cdbk_nb_high1[];
+extern const signed char cdbk_nb_high2[];
+
+/* Quantizes narrowband LSPs with 30 bits */
+void lsp_quant_nb(spx_lsp_t *lsp, spx_lsp_t *qlsp, int order, SpeexBits *bits);
+
+/* Decodes quantized narrowband LSPs */
+void lsp_unquant_nb(spx_lsp_t *lsp, int order, SpeexBits *bits);
+
+/* Quantizes low bit-rate narrowband LSPs with 18 bits */
+void lsp_quant_lbr(spx_lsp_t *lsp, spx_lsp_t *qlsp, int order, SpeexBits *bits);
+
+/* Decodes quantized low bit-rate narrowband LSPs */
+void lsp_unquant_lbr(spx_lsp_t *lsp, int order, SpeexBits *bits);
+
+/* Quantizes high-band LSPs with 12 bits */
+void lsp_quant_high(spx_lsp_t *lsp, spx_lsp_t *qlsp, int order, SpeexBits *bits);
+
+/* Decodes high-band LSPs */
+void lsp_unquant_high(spx_lsp_t *lsp, int order, SpeexBits *bits);
+
+#ifdef EPIC_48K
+/* Quantizes narrowband LSPs with 14 bits */
+void lsp_quant_48k(spx_lsp_t *lsp, spx_lsp_t *qlsp, int order, SpeexBits *bits);
+
+/* Decodes quantized narrowband LSPs (14 bits) */
+void lsp_unquant_48k(spx_lsp_t *lsp, int order, SpeexBits *bits);
+#endif
+
+
+#endif
diff --git a/3rdparty/speex/libspeex/quant_lsp_bfin.h b/3rdparty/speex/libspeex/quant_lsp_bfin.h
new file mode 100644
index 0000000..c884078
--- /dev/null
+++ b/3rdparty/speex/libspeex/quant_lsp_bfin.h
@@ -0,0 +1,165 @@
+/* Copyright (C) 2006 David Rowe */
+/**
+   @file quant_lsp_bfin.h
+   @author David Rowe
+   @brief Various compatibility routines for Speex (Blackfin version)
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define OVERRIDE_LSP_QUANT
+#ifdef OVERRIDE_LSP_QUANT
+
+/*
+  Note http://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html
+  well tell you all the magic resgister constraints used below
+  for gcc in-line asm.
+*/
+
+static int lsp_quant(
+  spx_word16_t      *x, 
+  const signed char *cdbk, 
+  int                nbVec, 
+  int                nbDim
+)
+{
+   int          j;
+   spx_word32_t best_dist=1<<30;
+   int          best_id=0;
+
+   __asm__ __volatile__
+     (
+"	%0 = 1 (X);\n\t"                       /* %0: best_dist */    
+"	%0 <<= 30;\n\t"     
+"	%1 = 0 (X);\n\t"                       /* %1: best_i         */
+"       P2 = %3\n\t"                           /* P2: ptr to cdbk    */
+"       R5 = 0;\n\t"                           /* R5: best cb entry  */
+
+"       R0 = %5;\n\t"                          /* set up circ addr   */
+"       R0 <<= 1;\n\t"
+"       L0 = R0;\n\t"                          
+"       I0 = %2;\n\t"                          /* %2: &x[0]          */
+"       B0 = %2;\n\t"                          
+
+"       R2.L = W [I0++];\n\t"
+"	LSETUP (lq1, lq2) LC0 = %4;\n\t"
+"lq1:	  R3 = 0;\n\t"                         /* R3: dist           */
+"	  LSETUP (lq3, lq4) LC1 = %5;\n\t"
+"lq3:       R1 = B [P2++] (X);\n\t"            
+"	    R1 <<= 5;\n\t"
+"	    R0.L = R2.L - R1.L || R2.L = W [I0++];\n\t"
+"	    R0 = R0.L*R0.L;\n\t"
+"lq4:	    R3 = R3 + R0;\n\t"
+
+"	  cc =R3<%0;\n\t"
+"	  if cc %0=R3;\n\t"
+"	  if cc %1=R5;\n\t"
+"lq2:     R5 += 1;\n\t"
+"         L0 = 0;\n\t"
+   : "=&d" (best_dist), "=&d" (best_id)
+   : "a" (x), "b" (cdbk), "a" (nbVec), "a" (nbDim)
+   : "I0", "P2", "R0", "R1", "R2", "R3", "R5", "L0", "B0", "A0"
+   );
+
+   for (j=0;j<nbDim;j++) {
+      x[j] = SUB16(x[j],SHL16((spx_word16_t)cdbk[best_id*nbDim+j],5));
+   }
+   return best_id;
+}
+#endif
+
+#define OVERRIDE_LSP_WEIGHT_QUANT
+#ifdef OVERRIDE_LSP_WEIGHT_QUANT
+
+/*
+  Note http://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html
+  well tell you all the magic resgister constraints used below
+  for gcc in-line asm.
+*/
+
+static int lsp_weight_quant(
+  spx_word16_t      *x, 
+  spx_word16_t      *weight, 
+  const signed char *cdbk, 
+  int                nbVec, 
+  int                nbDim
+)
+{
+   int          j;
+   spx_word32_t best_dist=1<<30;
+   int          best_id=0;
+
+   __asm__ __volatile__
+     (
+"	%0 = 1 (X);\n\t"                       /* %0: best_dist */    
+"	%0 <<= 30;\n\t"     
+"	%1 = 0 (X);\n\t"                       /* %1: best_i         */
+"       P2 = %4\n\t"                           /* P2: ptr to cdbk    */
+"       R5 = 0;\n\t"                           /* R5: best cb entry  */
+
+"       R0 = %6;\n\t"                          /* set up circ addr   */
+"       R0 <<= 1;\n\t"
+"       L0 = R0;\n\t"                          
+"       L1 = R0;\n\t"
+"       I0 = %2;\n\t"                          /* %2: &x[0]          */
+"	I1 = %3;\n\t"                          /* %3: &weight[0]     */
+"       B0 = %2;\n\t"                          
+"	B1 = %3;\n\t"                          
+
+"	LSETUP (lwq1, lwq2) LC0 = %5;\n\t"
+"lwq1:	  R3 = 0 (X);\n\t"                     /* R3: dist           */
+"	  LSETUP (lwq3, lwq4) LC1 = %6;\n\t"
+"lwq3:	    R0.L = W [I0++] || R2.L = W [I1++];\n\t"
+"           R1 = B [P2++] (X);\n\t"            
+"	    R1 <<= 5;\n\t"
+"	    R0.L = R0.L - R1.L;\n\t"
+"           R0 = R0.L*R0.L;\n\t"
+"	    A1 = R2.L*R0.L (M,IS);\n\t"
+"	    A1 = A1 >>> 16;\n\t"
+"	    R1 = (A1 += R2.L*R0.H) (IS);\n\t"
+"lwq4:	    R3 = R3 + R1;\n\t"
+
+"	  cc =R3<%0;\n\t"
+"	  if cc %0=R3;\n\t"
+"	  if cc %1=R5;\n\t"
+"lwq2:    R5 += 1;\n\t"
+"         L0 = 0;\n\t"
+"         L1 = 0;\n\t"
+   : "=&d" (best_dist), "=&d" (best_id)
+   : "a" (x), "a" (weight), "b" (cdbk), "a" (nbVec), "a" (nbDim)
+   : "I0", "I1", "P2", "R0", "R1", "R2", "R3", "R5", "A1",
+     "L0", "L1", "B0", "B1"
+   );
+
+   for (j=0;j<nbDim;j++) {
+      x[j] = SUB16(x[j],SHL16((spx_word16_t)cdbk[best_id*nbDim+j],5));
+   }
+   return best_id;
+}
+#endif
diff --git a/3rdparty/speex/libspeex/resample.c b/3rdparty/speex/libspeex/resample.c
new file mode 100644
index 0000000..45fac60
--- /dev/null
+++ b/3rdparty/speex/libspeex/resample.c
@@ -0,0 +1,1014 @@
+/* Copyright (C) 2007 Jean-Marc Valin
+      
+   File: resample.c
+   Arbitrary resampling code
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+   1. Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+   DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+   The design goals of this code are:
+      - Very fast algorithm
+      - SIMD-friendly algorithm
+      - Low memory requirement
+      - Good *perceptual* quality (and not best SNR)
+
+   The code is working, but it's in a very early stage, so it may have
+   artifacts, noise or subliminal messages from satan. Also, the API 
+   isn't stable and I can actually promise that I *will* change the API
+   some time in the future.
+
+TODO list:
+      - Variable calculation resolution depending on quality setting
+         - Single vs double in float mode
+         - 16-bit vs 32-bit (sinc only) in fixed-point mode
+      - Make sure the filter update works even when changing params 
+             after only a few samples procesed
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef OUTSIDE_SPEEX
+#include <stdlib.h>
+void *speex_alloc (int size) {return calloc(size,1);}
+void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);}
+void speex_free (void *ptr) {free(ptr);}
+#include "speex_resampler.h"
+#include "arch.h"
+#else /* OUTSIDE_SPEEX */
+               
+#include "speex/speex_resampler.h"
+#include "misc.h"
+#endif /* OUTSIDE_SPEEX */
+
+#include <math.h>
+
+#ifndef M_PI
+#define M_PI 3.14159263
+#endif
+
+#ifdef FIXED_POINT
+#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x)))  
+#else
+#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x))))  
+#endif
+               
+/*#define float double*/
+#define FILTER_SIZE 64
+#define OVERSAMPLE 8
+
+#define IMAX(a,b) ((a) > (b) ? (a) : (b))
+
+
+typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *);
+
+struct SpeexResamplerState_ {
+   spx_uint32_t in_rate;
+   spx_uint32_t out_rate;
+   spx_uint32_t num_rate;
+   spx_uint32_t den_rate;
+   
+   int    quality;
+   spx_uint32_t nb_channels;
+   spx_uint32_t filt_len;
+   spx_uint32_t mem_alloc_size;
+   int          int_advance;
+   int          frac_advance;
+   float  cutoff;
+   spx_uint32_t oversample;
+   int          initialised;
+   int          started;
+   
+   /* These are per-channel */
+   spx_int32_t  *last_sample;
+   spx_uint32_t *samp_frac_num;
+   spx_uint32_t *magic_samples;
+   
+   spx_word16_t *mem;
+   spx_word16_t *sinc_table;
+   spx_uint32_t sinc_table_length;
+   resampler_basic_func resampler_ptr;
+         
+   int    in_stride;
+   int    out_stride;
+} ;
+
+static double kaiser12_table[68] = {
+   0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076,
+   0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014,
+   0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601,
+   0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014,
+   0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490,
+   0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546,
+   0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178,
+   0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947,
+   0.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058,
+   0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438,
+   0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734,
+   0.00001000, 0.00000000};
+/*
+static double kaiser12_table[36] = {
+   0.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741,
+   0.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762,
+   0.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274,
+   0.17404546, 0.13794294, 0.10723616, 0.08164178, 0.06075685, 0.04409466,
+   0.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291,
+   0.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000};
+*/
+static double kaiser10_table[36] = {
+   0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446,
+   0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347,
+   0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962,
+   0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451,
+   0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739,
+   0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000};
+
+static double kaiser8_table[36] = {
+   0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200,
+   0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126,
+   0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272,
+   0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758,
+   0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490,
+   0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000};
+   
+static double kaiser6_table[36] = {
+   0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003,
+   0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565,
+   0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561,
+   0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058,
+   0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600,
+   0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000};
+
+struct FuncDef {
+   double *table;
+   int oversample;
+};
+      
+static struct FuncDef _KAISER12 = {kaiser12_table, 64};
+#define KAISER12 (&_KAISER12)
+/*static struct FuncDef _KAISER12 = {kaiser12_table, 32};
+#define KAISER12 (&_KAISER12)*/
+static struct FuncDef _KAISER10 = {kaiser10_table, 32};
+#define KAISER10 (&_KAISER10)
+static struct FuncDef _KAISER8 = {kaiser8_table, 32};
+#define KAISER8 (&_KAISER8)
+static struct FuncDef _KAISER6 = {kaiser6_table, 32};
+#define KAISER6 (&_KAISER6)
+
+struct QualityMapping {
+   int base_length;
+   int oversample;
+   float downsample_bandwidth;
+   float upsample_bandwidth;
+   struct FuncDef *window_func;
+};
+
+
+/* This table maps conversion quality to internal parameters. There are two
+   reasons that explain why the up-sampling bandwidth is larger than the 
+   down-sampling bandwidth:
+   1) When up-sampling, we can assume that the spectrum is already attenuated
+      close to the Nyquist rate (from an A/D or a previous resampling filter)
+   2) Any aliasing that occurs very close to the Nyquist rate will be masked
+      by the sinusoids/noise just below the Nyquist rate (guaranteed only for
+      up-sampling).
+*/
+static const struct QualityMapping quality_map[11] = {
+   {  8,  4, 0.830f, 0.860f, KAISER6 }, /* Q0 */
+   { 16,  4, 0.850f, 0.880f, KAISER6 }, /* Q1 */
+   { 32,  4, 0.882f, 0.910f, KAISER6 }, /* Q2 */  /* 82.3% cutoff ( ~60 dB stop) 6  */
+   { 48,  8, 0.895f, 0.917f, KAISER8 }, /* Q3 */  /* 84.9% cutoff ( ~80 dB stop) 8  */
+   { 64,  8, 0.921f, 0.940f, KAISER8 }, /* Q4 */  /* 88.7% cutoff ( ~80 dB stop) 8  */
+   { 80,  8, 0.922f, 0.940f, KAISER10}, /* Q5 */  /* 89.1% cutoff (~100 dB stop) 10 */
+   { 96,  8, 0.940f, 0.945f, KAISER10}, /* Q6 */  /* 91.5% cutoff (~100 dB stop) 10 */
+   {128, 16, 0.950f, 0.950f, KAISER10}, /* Q7 */  /* 93.1% cutoff (~100 dB stop) 10 */
+   {160, 16, 0.960f, 0.960f, KAISER10}, /* Q8 */  /* 94.5% cutoff (~100 dB stop) 10 */
+   {192, 16, 0.968f, 0.968f, KAISER12}, /* Q9 */  /* 95.5% cutoff (~100 dB stop) 10 */
+   {256, 16, 0.975f, 0.975f, KAISER12}, /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */
+};
+/*8,24,40,56,80,104,128,160,200,256,320*/
+static double compute_func(float x, struct FuncDef *func)
+{
+   float y, frac;
+   double interp[4];
+   int ind; 
+   y = x*func->oversample;
+   ind = (int)floor(y);
+   frac = (y-ind);
+   /* CSE with handle the repeated powers */
+   interp[3] =  -0.1666666667*frac + 0.1666666667*(frac*frac*frac);
+   interp[2] = frac + 0.5*(frac*frac) - 0.5*(frac*frac*frac);
+   /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
+   interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac);
+   /* Just to make sure we don't have rounding problems */
+   interp[1] = 1.f-interp[3]-interp[2]-interp[0];
+   
+   /*sum = frac*accum[1] + (1-frac)*accum[2];*/
+   return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3];
+}
+
+#if 0
+#include <stdio.h>
+int main(int argc, char **argv)
+{
+   int i;
+   for (i=0;i<256;i++)
+   {
+      printf ("%f\n", compute_func(i/256., KAISER12));
+   }
+   return 0;
+}
+#endif
+
+#ifdef FIXED_POINT
+/* The slow way of computing a sinc for the table. Should improve that some day */
+static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func)
+{
+   /*fprintf (stderr, "%f ", x);*/
+   float xx = x * cutoff;
+   if (fabs(x)<1e-6f)
+      return WORD2INT(32768.*cutoff);
+   else if (fabs(x) > .5f*N)
+      return 0;
+   /*FIXME: Can it really be any slower than this? */
+   return WORD2INT(32768.*cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func));
+}
+#else
+/* The slow way of computing a sinc for the table. Should improve that some day */
+static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func)
+{
+   /*fprintf (stderr, "%f ", x);*/
+   float xx = x * cutoff;
+   if (fabs(x)<1e-6)
+      return cutoff;
+   else if (fabs(x) > .5*N)
+      return 0;
+   /*FIXME: Can it really be any slower than this? */
+   return cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func);
+}
+#endif
+
+#ifdef FIXED_POINT
+static void cubic_coef(spx_word16_t x, spx_word16_t interp[4])
+{
+   /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
+   but I know it's MMSE-optimal on a sinc */
+   spx_word16_t x2, x3;
+   x2 = MULT16_16_P15(x, x);
+   x3 = MULT16_16_P15(x, x2);
+   interp[0] = PSHR32(MULT16_16(QCONST16(-0.16667f, 15),x) + MULT16_16(QCONST16(0.16667f, 15),x3),15);
+   interp[1] = EXTRACT16(EXTEND32(x) + SHR32(SUB32(EXTEND32(x2),EXTEND32(x3)),1));
+   interp[3] = PSHR32(MULT16_16(QCONST16(-0.33333f, 15),x) + MULT16_16(QCONST16(.5f,15),x2) - MULT16_16(QCONST16(0.16667f, 15),x3),15);
+   /* Just to make sure we don't have rounding problems */
+   interp[2] = Q15_ONE-interp[0]-interp[1]-interp[3];
+   if (interp[2]<32767)
+      interp[2]+=1;
+}
+#else
+static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4])
+{
+   /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
+   but I know it's MMSE-optimal on a sinc */
+   interp[0] =  -0.16667f*frac + 0.16667f*frac*frac*frac;
+   interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac;
+   /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
+   interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac;
+   /* Just to make sure we don't have rounding problems */
+   interp[2] = 1.-interp[0]-interp[1]-interp[3];
+}
+#endif
+
+static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
+{
+   int N = st->filt_len;
+   int out_sample = 0;
+   spx_word16_t *mem;
+   int last_sample = st->last_sample[channel_index];
+   spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
+   mem = st->mem + channel_index * st->mem_alloc_size;
+   while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
+   {
+      int j;
+      spx_word32_t sum=0;
+      
+      /* We already have all the filter coefficients pre-computed in the table */
+      const spx_word16_t *ptr;
+      /* Do the memory part */
+      for (j=0;last_sample-N+1+j < 0;j++)
+      {
+         sum += MULT16_16(mem[last_sample+j],st->sinc_table[samp_frac_num*st->filt_len+j]);
+      }
+      
+      /* Do the new part */
+      ptr = in+st->in_stride*(last_sample-N+1+j);
+      for (;j<N;j++)
+      {
+         sum += MULT16_16(*ptr,st->sinc_table[samp_frac_num*st->filt_len+j]);
+         ptr += st->in_stride;
+      }
+   
+      *out = PSHR32(sum,15);
+      out += st->out_stride;
+      out_sample++;
+      last_sample += st->int_advance;
+      samp_frac_num += st->frac_advance;
+      if (samp_frac_num >= st->den_rate)
+      {
+         samp_frac_num -= st->den_rate;
+         last_sample++;
+      }
+   }
+   st->last_sample[channel_index] = last_sample;
+   st->samp_frac_num[channel_index] = samp_frac_num;
+   return out_sample;
+}
+
+#ifdef FIXED_POINT
+#else
+/* This is the same as the previous function, except with a double-precision accumulator */
+static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
+{
+   int N = st->filt_len;
+   int out_sample = 0;
+   spx_word16_t *mem;
+   int last_sample = st->last_sample[channel_index];
+   spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
+   mem = st->mem + channel_index * st->mem_alloc_size;
+   while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
+   {
+      int j;
+      double sum=0;
+      
+      /* We already have all the filter coefficients pre-computed in the table */
+      const spx_word16_t *ptr;
+      /* Do the memory part */
+      for (j=0;last_sample-N+1+j < 0;j++)
+      {
+         sum += MULT16_16(mem[last_sample+j],(double)st->sinc_table[samp_frac_num*st->filt_len+j]);
+      }
+      
+      /* Do the new part */
+      ptr = in+st->in_stride*(last_sample-N+1+j);
+      for (;j<N;j++)
+      {
+         sum += MULT16_16(*ptr,(double)st->sinc_table[samp_frac_num*st->filt_len+j]);
+         ptr += st->in_stride;
+      }
+   
+      *out = sum;
+      out += st->out_stride;
+      out_sample++;
+      last_sample += st->int_advance;
+      samp_frac_num += st->frac_advance;
+      if (samp_frac_num >= st->den_rate)
+      {
+         samp_frac_num -= st->den_rate;
+         last_sample++;
+      }
+   }
+   st->last_sample[channel_index] = last_sample;
+   st->samp_frac_num[channel_index] = samp_frac_num;
+   return out_sample;
+}
+#endif
+
+static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
+{
+   int N = st->filt_len;
+   int out_sample = 0;
+   spx_word16_t *mem;
+   int last_sample = st->last_sample[channel_index];
+   spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
+   mem = st->mem + channel_index * st->mem_alloc_size;
+   while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
+   {
+      int j;
+      spx_word32_t sum=0;
+      
+      /* We need to interpolate the sinc filter */
+      spx_word32_t accum[4] = {0.f,0.f, 0.f, 0.f};
+      spx_word16_t interp[4];
+      const spx_word16_t *ptr;
+      int offset;
+      spx_word16_t frac;
+      offset = samp_frac_num*st->oversample/st->den_rate;
+#ifdef FIXED_POINT
+      frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);
+#else
+      frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;
+#endif
+         /* This code is written like this to make it easy to optimise with SIMD.
+      For most DSPs, it would be best to split the loops in two because most DSPs 
+      have only two accumulators */
+      for (j=0;last_sample-N+1+j < 0;j++)
+      {
+         spx_word16_t curr_mem = mem[last_sample+j];
+         accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
+         accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
+         accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]);
+         accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
+      }
+      ptr = in+st->in_stride*(last_sample-N+1+j);
+      /* Do the new part */
+      for (;j<N;j++)
+      {
+         spx_word16_t curr_in = *ptr;
+         ptr += st->in_stride;
+         accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
+         accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
+         accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
+         accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
+      }
+      cubic_coef(frac, interp);
+      sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]);
+   
+      *out = PSHR32(sum,15);
+      out += st->out_stride;
+      out_sample++;
+      last_sample += st->int_advance;
+      samp_frac_num += st->frac_advance;
+      if (samp_frac_num >= st->den_rate)
+      {
+         samp_frac_num -= st->den_rate;
+         last_sample++;
+      }
+   }
+   st->last_sample[channel_index] = last_sample;
+   st->samp_frac_num[channel_index] = samp_frac_num;
+   return out_sample;
+}
+
+#ifdef FIXED_POINT
+#else
+/* This is the same as the previous function, except with a double-precision accumulator */
+static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
+{
+   int N = st->filt_len;
+   int out_sample = 0;
+   spx_word16_t *mem;
+   int last_sample = st->last_sample[channel_index];
+   spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
+   mem = st->mem + channel_index * st->mem_alloc_size;
+   while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
+   {
+      int j;
+      spx_word32_t sum=0;
+      
+      /* We need to interpolate the sinc filter */
+      double accum[4] = {0.f,0.f, 0.f, 0.f};
+      float interp[4];
+      const spx_word16_t *ptr;
+      float alpha = ((float)samp_frac_num)/st->den_rate;
+      int offset = samp_frac_num*st->oversample/st->den_rate;
+      float frac = alpha*st->oversample - offset;
+         /* This code is written like this to make it easy to optimise with SIMD.
+      For most DSPs, it would be best to split the loops in two because most DSPs 
+      have only two accumulators */
+      for (j=0;last_sample-N+1+j < 0;j++)
+      {
+         double curr_mem = mem[last_sample+j];
+         accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
+         accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
+         accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]);
+         accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
+      }
+      ptr = in+st->in_stride*(last_sample-N+1+j);
+      /* Do the new part */
+      for (;j<N;j++)
+      {
+         double curr_in = *ptr;
+         ptr += st->in_stride;
+         accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
+         accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
+         accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
+         accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
+      }
+      cubic_coef(frac, interp);
+      sum = interp[0]*accum[0] + interp[1]*accum[1] + interp[2]*accum[2] + interp[3]*accum[3];
+   
+      *out = PSHR32(sum,15);
+      out += st->out_stride;
+      out_sample++;
+      last_sample += st->int_advance;
+      samp_frac_num += st->frac_advance;
+      if (samp_frac_num >= st->den_rate)
+      {
+         samp_frac_num -= st->den_rate;
+         last_sample++;
+      }
+   }
+   st->last_sample[channel_index] = last_sample;
+   st->samp_frac_num[channel_index] = samp_frac_num;
+   return out_sample;
+}
+#endif
+
+static void update_filter(SpeexResamplerState *st)
+{
+   spx_uint32_t old_length;
+   
+   old_length = st->filt_len;
+   st->oversample = quality_map[st->quality].oversample;
+   st->filt_len = quality_map[st->quality].base_length;
+   
+   if (st->num_rate > st->den_rate)
+   {
+      /* down-sampling */
+      st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate;
+      /* FIXME: divide the numerator and denominator by a certain amount if they're too large */
+      st->filt_len = st->filt_len*st->num_rate / st->den_rate;
+      /* Round down to make sure we have a multiple of 4 */
+      st->filt_len &= (~0x3);
+   } else {
+      /* up-sampling */
+      st->cutoff = quality_map[st->quality].upsample_bandwidth;
+   }
+
+   /* Choose the resampling type that requires the least amount of memory */
+   if (st->den_rate <= st->oversample)
+   {
+      spx_uint32_t i;
+      if (!st->sinc_table)
+         st->sinc_table = (spx_word16_t *)speex_alloc(st->filt_len*st->den_rate*sizeof(spx_word16_t));
+      else if (st->sinc_table_length < st->filt_len*st->den_rate)
+      {
+         st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,st->filt_len*st->den_rate*sizeof(spx_word16_t));
+         st->sinc_table_length = st->filt_len*st->den_rate;
+      }
+      for (i=0;i<st->den_rate;i++)
+      {
+         spx_uint32_t j;
+         for (j=0;j<st->filt_len;j++)
+         {
+            st->sinc_table[i*st->filt_len+j] = sinc(st->cutoff,((j-st->filt_len/2+1)-((float)i)/st->den_rate), st->filt_len, quality_map[st->quality].window_func);
+         }
+      }
+#ifdef FIXED_POINT
+      st->resampler_ptr = resampler_basic_direct_single;
+#else
+      if (st->quality>8)
+         st->resampler_ptr = resampler_basic_direct_double;
+      else
+         st->resampler_ptr = resampler_basic_direct_single;
+#endif
+      /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/
+   } else {
+      spx_int32_t i;
+      if (!st->sinc_table)
+         st->sinc_table = (spx_word16_t *)speex_alloc((st->filt_len*st->oversample+8)*sizeof(spx_word16_t));
+      else if (st->sinc_table_length < st->filt_len*st->oversample+8)
+      {
+         st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,(st->filt_len*st->oversample+8)*sizeof(spx_word16_t));
+         st->sinc_table_length = st->filt_len*st->oversample+8;
+      }
+      for (i=-4;i<(spx_int32_t)(st->oversample*st->filt_len+4);i++)
+         st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len, quality_map[st->quality].window_func);
+#ifdef FIXED_POINT
+      st->resampler_ptr = resampler_basic_interpolate_single;
+#else
+      if (st->quality>8)
+         st->resampler_ptr = resampler_basic_interpolate_double;
+      else
+         st->resampler_ptr = resampler_basic_interpolate_single;
+#endif
+      /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/
+   }
+   st->int_advance = st->num_rate/st->den_rate;
+   st->frac_advance = st->num_rate%st->den_rate;
+
+   if (!st->mem)
+   {
+      spx_uint32_t i;
+      st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t));
+      for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
+         st->mem[i] = 0;
+      st->mem_alloc_size = st->filt_len-1;
+      /*speex_warning("init filter");*/
+   } else if (!st->started)
+   {
+      spx_uint32_t i;
+      st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t));
+      for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
+         st->mem[i] = 0;
+      st->mem_alloc_size = st->filt_len-1;
+      /*speex_warning("reinit filter");*/
+   } else if (st->filt_len > old_length)
+   {
+      spx_uint32_t i;
+      /* Increase the filter length */
+      /*speex_warning("increase filter size");*/
+      int old_alloc_size = st->mem_alloc_size;
+      if (st->filt_len-1 > st->mem_alloc_size)
+      {
+         st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t));
+         st->mem_alloc_size = st->filt_len-1;
+      }
+      for (i=0;i<st->nb_channels;i++)
+      {
+         spx_uint32_t j;
+         /* Copy data going backward */
+         for (j=0;j<old_length-1;j++)
+            st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*old_alloc_size+(old_length-2-j)];
+         /* Then put zeros for lack of anything better */
+         for (;j<st->filt_len-1;j++)
+            st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0;
+         /* Adjust last_sample */
+         st->last_sample[i] += (st->filt_len - old_length)/2;
+      }
+   } else if (st->filt_len < old_length)
+   {
+      spx_uint32_t i;
+      /* Reduce filter length, this a bit tricky */
+      /*speex_warning("decrease filter size (unimplemented)");*/
+      /* Adjust last_sample (which will likely end up negative) */
+      /*st->last_sample += (st->filt_len - old_length)/2;*/
+      for (i=0;i<st->nb_channels;i++)
+      {
+         spx_uint32_t j;
+         st->magic_samples[i] = (old_length - st->filt_len)/2;
+         /* Copy data going backward */
+         for (j=0;j<st->filt_len-1+st->magic_samples[i];j++)
+            st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]];
+      }
+   }
+
+}
+
+SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality)
+{
+   return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality);
+}
+
+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)
+{
+   spx_uint32_t i;
+   SpeexResamplerState *st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState));
+   st->initialised = 0;
+   st->started = 0;
+   st->in_rate = 0;
+   st->out_rate = 0;
+   st->num_rate = 0;
+   st->den_rate = 0;
+   st->quality = -1;
+   st->sinc_table_length = 0;
+   st->mem_alloc_size = 0;
+   st->filt_len = 0;
+   st->mem = 0;
+   st->resampler_ptr = 0;
+         
+   st->cutoff = 1.f;
+   st->nb_channels = nb_channels;
+   st->in_stride = 1;
+   st->out_stride = 1;
+   
+   /* Per channel data */
+   st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int));
+   st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));
+   st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));
+   for (i=0;i<nb_channels;i++)
+   {
+      st->last_sample[i] = 0;
+      st->magic_samples[i] = 0;
+      st->samp_frac_num[i] = 0;
+   }
+
+   speex_resampler_set_quality(st, quality);
+   speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate);
+
+   
+   update_filter(st);
+   
+   st->initialised = 1;
+   return st;
+}
+
+void speex_resampler_destroy(SpeexResamplerState *st)
+{
+   speex_free(st->mem);
+   speex_free(st->sinc_table);
+   speex_free(st->last_sample);
+   speex_free(st->magic_samples);
+   speex_free(st->samp_frac_num);
+   speex_free(st);
+}
+
+
+
+static void speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
+{
+   int j=0;
+   int N = st->filt_len;
+   int out_sample = 0;
+   spx_word16_t *mem;
+   spx_uint32_t tmp_out_len = 0;
+   mem = st->mem + channel_index * st->mem_alloc_size;
+   st->started = 1;
+   
+   /* Handle the case where we have samples left from a reduction in filter length */
+   if (st->magic_samples[channel_index])
+   {
+      spx_uint32_t tmp_in_len;
+      spx_uint32_t tmp_magic;
+      tmp_in_len = st->magic_samples[channel_index];
+      tmp_out_len = *out_len;
+      /* FIXME: Need to handle the case where the out array is too small */
+      /* magic_samples needs to be set to zero to avoid infinite recursion */
+      tmp_magic = st->magic_samples[channel_index];
+      st->magic_samples[channel_index] = 0;
+      speex_resampler_process_native(st, channel_index, mem+N-1, &tmp_in_len, out, &tmp_out_len);
+      /*speex_warning_int("extra samples:", tmp_out_len);*/
+      /* If we couldn't process all "magic" input samples, save the rest for next time */
+      if (tmp_in_len < tmp_magic)
+      {
+         spx_uint32_t i;
+         st->magic_samples[channel_index] = tmp_magic-tmp_in_len;
+         for (i=0;i<st->magic_samples[channel_index];i++)
+            mem[N-1+i]=mem[N-1+i+tmp_in_len];
+      }
+      out += tmp_out_len;
+   }
+   
+   /* Call the right resampler through the function ptr */
+   out_sample = st->resampler_ptr(st, channel_index, in, in_len, out, out_len);
+   
+   if (st->last_sample[channel_index] < (spx_int32_t)*in_len)
+      *in_len = st->last_sample[channel_index];
+   *out_len = out_sample+tmp_out_len;
+   st->last_sample[channel_index] -= *in_len;
+   
+   for (j=0;j<N-1-(spx_int32_t)*in_len;j++)
+      mem[j] = mem[j+*in_len];
+   for (;j<N-1;j++)
+      mem[j] = in[st->in_stride*(j+*in_len-N+1)];
+   
+}
+
+#define FIXED_STACK_ALLOC 1024
+
+#ifdef FIXED_POINT
+void speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
+{
+   spx_uint32_t i;
+   int istride_save, ostride_save;
+#ifdef VAR_ARRAYS
+   spx_word16_t x[*in_len];
+   spx_word16_t y[*out_len];
+   /*VARDECL(spx_word16_t *x);
+   VARDECL(spx_word16_t *y);
+   ALLOC(x, *in_len, spx_word16_t);
+   ALLOC(y, *out_len, spx_word16_t);*/
+   istride_save = st->in_stride;
+   ostride_save = st->out_stride;
+   for (i=0;i<*in_len;i++)
+      x[i] = WORD2INT(in[i*st->in_stride]);
+   st->in_stride = st->out_stride = 1;
+   speex_resampler_process_native(st, channel_index, x, in_len, y, out_len);
+   st->in_stride = istride_save;
+   st->out_stride = ostride_save;
+   for (i=0;i<*out_len;i++)
+      out[i*st->out_stride] = y[i];
+#else
+   spx_word16_t x[FIXED_STACK_ALLOC];
+   spx_word16_t y[FIXED_STACK_ALLOC];
+   spx_uint32_t ilen=*in_len, olen=*out_len;
+   istride_save = st->in_stride;
+   ostride_save = st->out_stride;
+   while (ilen && olen)
+   {
+      spx_uint32_t ichunk, ochunk;
+      ichunk = ilen;
+      ochunk = olen;
+      if (ichunk>FIXED_STACK_ALLOC)
+         ichunk=FIXED_STACK_ALLOC;
+      if (ochunk>FIXED_STACK_ALLOC)
+         ochunk=FIXED_STACK_ALLOC;
+      for (i=0;i<ichunk;i++)
+         x[i] = WORD2INT(in[i*st->in_stride]);
+      st->in_stride = st->out_stride = 1;
+      speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk);
+      st->in_stride = istride_save;
+      st->out_stride = ostride_save;
+      for (i=0;i<ochunk;i++)
+         out[i*st->out_stride] = y[i];
+      out += ochunk;
+      in += ichunk;
+      ilen -= ichunk;
+      olen -= ochunk;
+   }
+   *in_len -= ilen;
+   *out_len -= olen;   
+#endif
+}
+void 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)
+{
+   speex_resampler_process_native(st, channel_index, in, in_len, out, out_len);
+}
+#else
+void 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)
+{
+   speex_resampler_process_native(st, channel_index, in, in_len, out, out_len);
+}
+void speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
+{
+   spx_uint32_t i;
+   int istride_save, ostride_save;
+#ifdef VAR_ARRAYS
+   spx_word16_t x[*in_len];
+   spx_word16_t y[*out_len];
+   /*VARDECL(spx_word16_t *x);
+   VARDECL(spx_word16_t *y);
+   ALLOC(x, *in_len, spx_word16_t);
+   ALLOC(y, *out_len, spx_word16_t);*/
+   istride_save = st->in_stride;
+   ostride_save = st->out_stride;
+   for (i=0;i<*in_len;i++)
+      x[i] = in[i*st->in_stride];
+   st->in_stride = st->out_stride = 1;
+   speex_resampler_process_native(st, channel_index, x, in_len, y, out_len);
+   st->in_stride = istride_save;
+   st->out_stride = ostride_save;
+   for (i=0;i<*out_len;i++)
+      out[i*st->out_stride] = WORD2INT(y[i]);
+#else
+   spx_word16_t x[FIXED_STACK_ALLOC];
+   spx_word16_t y[FIXED_STACK_ALLOC];
+   spx_uint32_t ilen=*in_len, olen=*out_len;
+   istride_save = st->in_stride;
+   ostride_save = st->out_stride;
+   while (ilen && olen)
+   {
+      spx_uint32_t ichunk, ochunk;
+      ichunk = ilen;
+      ochunk = olen;
+      if (ichunk>FIXED_STACK_ALLOC)
+         ichunk=FIXED_STACK_ALLOC;
+      if (ochunk>FIXED_STACK_ALLOC)
+         ochunk=FIXED_STACK_ALLOC;
+      for (i=0;i<ichunk;i++)
+         x[i] = in[i*st->in_stride];
+      st->in_stride = st->out_stride = 1;
+      speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk);
+      st->in_stride = istride_save;
+      st->out_stride = ostride_save;
+      for (i=0;i<ochunk;i++)
+         out[i*st->out_stride] = WORD2INT(y[i]);
+      out += ochunk;
+      in += ichunk;
+      ilen -= ichunk;
+      olen -= ochunk;
+   }
+   *in_len -= ilen;
+   *out_len -= olen;   
+#endif
+}
+#endif
+
+void speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
+{
+   spx_uint32_t i;
+   int istride_save, ostride_save;
+   istride_save = st->in_stride;
+   ostride_save = st->out_stride;
+   st->in_stride = st->out_stride = st->nb_channels;
+   for (i=0;i<st->nb_channels;i++)
+   {
+      speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len);
+   }
+   st->in_stride = istride_save;
+   st->out_stride = ostride_save;
+}
+
+void speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
+{
+   spx_uint32_t i;
+   int istride_save, ostride_save;
+   istride_save = st->in_stride;
+   ostride_save = st->out_stride;
+   st->in_stride = st->out_stride = st->nb_channels;
+   for (i=0;i<st->nb_channels;i++)
+   {
+      speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len);
+   }
+   st->in_stride = istride_save;
+   st->out_stride = ostride_save;
+}
+
+void speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate)
+{
+   speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate);
+}
+
+void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate)
+{
+   *in_rate = st->in_rate;
+   *out_rate = st->out_rate;
+}
+
+void speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate)
+{
+   int fact;
+   if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den)
+      return;
+   
+   st->in_rate = in_rate;
+   st->out_rate = out_rate;
+   st->num_rate = ratio_num;
+   st->den_rate = ratio_den;
+   /* FIXME: This is terribly inefficient, but who cares (at least for now)? */
+   for (fact=2;fact<=sqrt(IMAX(in_rate, out_rate));fact++)
+   {
+      while ((st->num_rate % fact == 0) && (st->den_rate % fact == 0))
+      {
+         st->num_rate /= fact;
+         st->den_rate /= fact;
+      }
+   }
+      
+   if (st->initialised)
+      update_filter(st);
+}
+
+void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den)
+{
+   *ratio_num = st->num_rate;
+   *ratio_den = st->den_rate;
+}
+
+void speex_resampler_set_quality(SpeexResamplerState *st, int quality)
+{
+   if (quality < 0)
+      quality = 0;
+   if (quality > 10)
+      quality = 10;
+   if (st->quality == quality)
+      return;
+   st->quality = quality;
+   if (st->initialised)
+      update_filter(st);
+}
+
+void speex_resampler_get_quality(SpeexResamplerState *st, int *quality)
+{
+   *quality = st->quality;
+}
+
+void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride)
+{
+   st->in_stride = stride;
+}
+
+void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride)
+{
+   *stride = st->in_stride;
+}
+
+void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride)
+{
+   st->out_stride = stride;
+}
+
+void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride)
+{
+   *stride = st->out_stride;
+}
+
+void speex_resampler_skip_zeros(SpeexResamplerState *st)
+{
+   spx_uint32_t i;
+   for (i=0;i<st->nb_channels;i++)
+      st->last_sample[i] = st->filt_len/2;
+}
+
+void speex_resampler_reset_mem(SpeexResamplerState *st)
+{
+   spx_uint32_t i;
+   for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
+      st->mem[i] = 0;
+}
+
diff --git a/3rdparty/speex/libspeex/sb_celp.c b/3rdparty/speex/libspeex/sb_celp.c
new file mode 100644
index 0000000..50b9824
--- /dev/null
+++ b/3rdparty/speex/libspeex/sb_celp.c
@@ -0,0 +1,1480 @@
+/* Copyright (C) 2002-2006 Jean-Marc Valin 
+   File: sb_celp.c
+
+   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 <math.h>
+#include "sb_celp.h"
+#include "stdlib.h"
+#include "filters.h"
+#include "lpc.h"
+#include "lsp.h"
+#include "stack_alloc.h"
+#include "cb_search.h"
+#include "quant_lsp.h"
+#include "vq.h"
+#include "ltp.h"
+#include "misc.h"
+#include "math_approx.h"
+
+/* Default size for the encoder and decoder stack (can be changed at compile time).
+   This does not apply when using variable-size arrays or alloca. */
+#ifndef SB_ENC_STACK
+#define SB_ENC_STACK (10000*sizeof(spx_sig_t))
+#endif
+
+#ifndef SB_DEC_STACK
+#define SB_DEC_STACK (6000*sizeof(spx_sig_t))
+#endif
+
+
+#ifdef DISABLE_WIDEBAND
+void *sb_encoder_init(const SpeexMode *m)
+{
+   speex_error("Wideband and Ultra-wideband are disabled");
+   return NULL;
+}
+void sb_encoder_destroy(void *state)
+{
+   speex_error("Wideband and Ultra-wideband are disabled");
+}
+int sb_encode(void *state, void *vin, SpeexBits *bits)
+{
+   speex_error("Wideband and Ultra-wideband are disabled");
+   return -2;
+}
+void *sb_decoder_init(const SpeexMode *m)
+{
+   speex_error("Wideband and Ultra-wideband are disabled");
+   return NULL;
+}
+void sb_decoder_destroy(void *state)
+{
+   speex_error("Wideband and Ultra-wideband are disabled");
+}
+int sb_decode(void *state, SpeexBits *bits, void *vout)
+{
+   speex_error("Wideband and Ultra-wideband are disabled");
+   return -2;
+}
+int sb_encoder_ctl(void *state, int request, void *ptr)
+{
+   speex_error("Wideband and Ultra-wideband are disabled");
+   return -2;
+}
+int sb_decoder_ctl(void *state, int request, void *ptr)
+{
+   speex_error("Wideband and Ultra-wideband are disabled");
+   return -2;
+}
+#else
+
+
+#ifndef M_PI
+#define M_PI           3.14159265358979323846  /* pi */
+#endif
+
+#define sqr(x) ((x)*(x))
+
+#define SUBMODE(x) st->submodes[st->submodeID]->x
+
+#ifdef FIXED_POINT
+static const spx_word16_t gc_quant_bound[16] = {125, 164, 215, 282, 370, 484, 635, 832, 1090, 1428, 1871, 2452, 3213, 4210, 5516, 7228};
+static const spx_word16_t fold_quant_bound[32] = {
+   39, 44, 50, 57, 64, 73, 83, 94,
+   106, 120, 136, 154, 175, 198, 225, 255,
+   288, 327, 370, 420, 476, 539, 611, 692,
+   784, 889, 1007, 1141, 1293, 1465, 1660, 1881};
+#define LSP_MARGIN 410
+#define LSP_DELTA1 6553
+#define LSP_DELTA2 1638
+
+#else
+
+static const spx_word16_t gc_quant_bound[16] = {
+      0.97979, 1.28384, 1.68223, 2.20426, 2.88829, 3.78458, 4.95900, 6.49787, 
+      8.51428, 11.15642, 14.61846, 19.15484, 25.09895, 32.88761, 43.09325, 56.46588};
+static const spx_word16_t fold_quant_bound[32] = {
+   0.30498, 0.34559, 0.39161, 0.44375, 0.50283, 0.56979, 0.64565, 0.73162,
+   0.82903, 0.93942, 1.06450, 1.20624, 1.36685, 1.54884, 1.75506, 1.98875,
+   2.25355, 2.55360, 2.89361, 3.27889, 3.71547, 4.21018, 4.77076, 5.40598,
+   6.12577, 6.94141, 7.86565, 8.91295, 10.09969, 11.44445, 12.96826, 14.69497};
+
+#define LSP_MARGIN .05
+#define LSP_DELTA1 .2
+#define LSP_DELTA2 .05
+
+#endif
+
+#define QMF_ORDER 64
+
+#ifdef FIXED_POINT
+static const spx_word16_t h0[64] = {2, -7, -7, 18, 15, -39, -25, 75, 35, -130, -41, 212, 38, -327, -17, 483, -32, -689, 124, 956, -283, -1307, 543, 1780, -973, -2467, 1733, 3633, -3339, -6409, 9059, 30153, 30153, 9059, -6409, -3339, 3633, 1733, -2467, -973, 1780, 543, -1307, -283, 956, 124, -689, -32, 483, -17, -327, 38, 212, -41, -130, 35, 75, -25, -39, 15, 18, -7, -7, 2};
+
+#else
+static const float h0[64] = {
+   3.596189e-05f, -0.0001123515f,
+   -0.0001104587f, 0.0002790277f,
+   0.0002298438f, -0.0005953563f,
+   -0.0003823631f, 0.00113826f,
+   0.0005308539f, -0.001986177f,
+   -0.0006243724f, 0.003235877f,
+   0.0005743159f, -0.004989147f,
+   -0.0002584767f, 0.007367171f,
+   -0.0004857935f, -0.01050689f,
+   0.001894714f, 0.01459396f,
+   -0.004313674f, -0.01994365f,
+   0.00828756f, 0.02716055f,
+   -0.01485397f, -0.03764973f,
+   0.026447f, 0.05543245f,
+   -0.05095487f, -0.09779096f,
+   0.1382363f, 0.4600981f,
+   0.4600981f, 0.1382363f,
+   -0.09779096f, -0.05095487f,
+   0.05543245f, 0.026447f,
+   -0.03764973f, -0.01485397f,
+   0.02716055f, 0.00828756f,
+   -0.01994365f, -0.004313674f,
+   0.01459396f, 0.001894714f,
+   -0.01050689f, -0.0004857935f,
+   0.007367171f, -0.0002584767f,
+   -0.004989147f, 0.0005743159f,
+   0.003235877f, -0.0006243724f,
+   -0.001986177f, 0.0005308539f,
+   0.00113826f, -0.0003823631f,
+   -0.0005953563f, 0.0002298438f,
+   0.0002790277f, -0.0001104587f,
+   -0.0001123515f, 3.596189e-05f
+};
+
+#endif
+
+extern const spx_word16_t lpc_window[];
+
+
+void *sb_encoder_init(const SpeexMode *m)
+{
+   int i;
+   spx_int32_t tmp;
+   SBEncState *st;
+   const SpeexSBMode *mode;
+
+   st = (SBEncState*)speex_alloc(sizeof(SBEncState));
+   if (!st)
+      return NULL;
+   st->mode = m;
+   mode = (const SpeexSBMode*)m->mode;
+
+
+   st->st_low = speex_encoder_init(mode->nb_mode);
+#if defined(VAR_ARRAYS) || defined (USE_ALLOCA)
+   st->stack = NULL;
+#else
+   /*st->stack = (char*)speex_alloc_scratch(SB_ENC_STACK);*/
+   speex_encoder_ctl(st->st_low, SPEEX_GET_STACK, &st->stack);
+#endif
+
+   st->full_frame_size = 2*mode->frameSize;
+   st->frame_size = mode->frameSize;
+   st->subframeSize = mode->subframeSize;
+   st->nbSubframes = mode->frameSize/mode->subframeSize;
+   st->windowSize = st->frame_size+st->subframeSize;
+   st->lpcSize=mode->lpcSize;
+   st->bufSize=mode->bufSize;
+
+   st->encode_submode = 1;
+   st->submodes=mode->submodes;
+   st->submodeSelect = st->submodeID=mode->defaultSubmode;
+   
+   tmp=9;
+   speex_encoder_ctl(st->st_low, SPEEX_SET_QUALITY, &tmp);
+   tmp=1;
+   speex_encoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, &tmp);
+
+   st->lag_factor = mode->lag_factor;
+   st->lpc_floor = mode->lpc_floor;
+   st->gamma1=mode->gamma1;
+   st->gamma2=mode->gamma2;
+   st->first=1;
+
+   st->high=(spx_word16_t*)speex_alloc((st->windowSize-st->frame_size)*sizeof(spx_word16_t));
+
+   st->h0_mem=(spx_word16_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word16_t));
+   st->h1_mem=(spx_word16_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word16_t));
+
+   st->window= lpc_window;
+
+   st->lagWindow = (spx_word16_t*)speex_alloc((st->lpcSize+1)*sizeof(spx_word16_t));
+   for (i=0;i<st->lpcSize+1;i++)
+      st->lagWindow[i]=16384*exp(-.5*sqr(2*M_PI*st->lag_factor*i));
+
+   st->old_lsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t));
+   st->old_qlsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t));
+   st->interp_qlpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t));
+   st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t));
+   st->exc_rms = (spx_word16_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word16_t));
+   st->innov_rms_save = NULL;
+   
+   st->mem_sp = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t));
+   st->mem_sp2 = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t));
+   st->mem_sw = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t));
+
+   for (i=0;i<st->lpcSize;i++)
+   {
+      st->old_lsp[i]=LSP_SCALING*(M_PI*((float)(i+1)))/(st->lpcSize+1);
+   }
+
+   st->vbr_quality = 8;
+   st->vbr_enabled = 0;
+   st->vbr_max = 0;
+   st->vbr_max_high = 20000;  /* We just need a big value here */
+   st->vad_enabled = 0;
+   st->abr_enabled = 0;
+   st->relative_quality=0;
+
+   st->complexity=2;
+   speex_encoder_ctl(st->st_low, SPEEX_GET_SAMPLING_RATE, &st->sampling_rate);
+   st->sampling_rate*=2;
+#ifdef ENABLE_VALGRIND
+   VALGRIND_MAKE_READABLE(st, (st->stack-(char*)st));
+#endif
+   return st;
+}
+
+void sb_encoder_destroy(void *state)
+{
+   SBEncState *st=(SBEncState*)state;
+
+   speex_encoder_destroy(st->st_low);
+#if !(defined(VAR_ARRAYS) || defined (USE_ALLOCA))
+   /*speex_free_scratch(st->stack);*/
+#endif
+
+   speex_free(st->high);
+
+   speex_free(st->h0_mem);
+   speex_free(st->h1_mem);
+
+   speex_free(st->lagWindow);
+
+   speex_free(st->old_lsp);
+   speex_free(st->old_qlsp);
+   speex_free(st->interp_qlpc);
+   speex_free(st->pi_gain);
+   speex_free(st->exc_rms);
+
+   speex_free(st->mem_sp);
+   speex_free(st->mem_sp2);
+   speex_free(st->mem_sw);
+
+   
+   speex_free(st);
+}
+
+
+int sb_encode(void *state, void *vin, SpeexBits *bits)
+{
+   SBEncState *st;
+   int i, roots, sub;
+   char *stack;
+   VARDECL(spx_mem_t *mem);
+   VARDECL(spx_sig_t *innov);
+   VARDECL(spx_word16_t *target);
+   VARDECL(spx_word16_t *syn_resp);
+   VARDECL(spx_word32_t *low_pi_gain);
+   spx_word16_t *low;
+   spx_word16_t *high;
+   VARDECL(spx_word16_t *low_exc_rms);
+   VARDECL(spx_word16_t *low_innov_rms);
+   const SpeexSBMode *mode;
+   spx_int32_t dtx;
+   spx_word16_t *in = (spx_word16_t*)vin;
+   spx_word16_t e_low=0, e_high=0;
+   VARDECL(spx_coef_t *lpc);
+   VARDECL(spx_coef_t *interp_lpc);
+   VARDECL(spx_coef_t *bw_lpc1);
+   VARDECL(spx_coef_t *bw_lpc2);
+   VARDECL(spx_lsp_t *lsp);
+   VARDECL(spx_lsp_t *qlsp);
+   VARDECL(spx_lsp_t *interp_lsp);
+   VARDECL(spx_lsp_t *interp_qlsp);
+      
+   st = (SBEncState*)state;
+   stack=st->stack;
+   mode = (const SpeexSBMode*)(st->mode->mode);
+   low = in;
+   high = in+st->frame_size;
+   
+   /* High-band buffering / sync with low band */
+   /* Compute the two sub-bands by filtering with QMF h0*/
+   qmf_decomp(in, h0, low, high, st->full_frame_size, QMF_ORDER, st->h0_mem, stack);
+   
+   if (st->vbr_enabled || st->vad_enabled)
+   {
+      /* Need to compute things here before the signal is trashed by the encoder */
+      /*FIXME: Are the two signals (low, high) in sync? */
+      e_low = compute_rms16(low, st->frame_size);
+      e_high = compute_rms16(high, st->frame_size);
+   }
+   ALLOC(low_innov_rms, st->nbSubframes, spx_word16_t);
+   speex_encoder_ctl(st->st_low, SPEEX_SET_INNOVATION_SAVE, low_innov_rms);
+   /* Encode the narrowband part*/
+   speex_encode_native(st->st_low, low, bits);
+
+   high = high - (st->windowSize-st->frame_size);
+   for (i=0;i<st->windowSize-st->frame_size;i++)
+      high[i] = st->high[i];
+   for (i=0;i<st->windowSize-st->frame_size;i++)
+      st->high[i] = high[i+st->frame_size];
+   
+
+   ALLOC(low_pi_gain, st->nbSubframes, spx_word32_t);
+   ALLOC(low_exc_rms, st->nbSubframes, spx_word16_t);
+   speex_encoder_ctl(st->st_low, SPEEX_GET_PI_GAIN, low_pi_gain);
+   speex_encoder_ctl(st->st_low, SPEEX_GET_EXC, low_exc_rms);
+   
+   speex_encoder_ctl(st->st_low, SPEEX_GET_LOW_MODE, &dtx);
+
+   if (dtx==0)
+      dtx=1;
+   else
+      dtx=0;
+
+   ALLOC(lpc, st->lpcSize, spx_coef_t);
+   ALLOC(interp_lpc, st->lpcSize, spx_coef_t);
+   ALLOC(bw_lpc1, st->lpcSize, spx_coef_t);
+   ALLOC(bw_lpc2, st->lpcSize, spx_coef_t);
+   
+   ALLOC(lsp, st->lpcSize, spx_lsp_t);
+   ALLOC(qlsp, st->lpcSize, spx_lsp_t);
+   ALLOC(interp_lsp, st->lpcSize, spx_lsp_t);
+   ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t);
+   
+   {
+      VARDECL(spx_word16_t *autocorr);
+      VARDECL(spx_word16_t *w_sig);
+      ALLOC(autocorr, st->lpcSize+1, spx_word16_t);
+      ALLOC(w_sig, st->windowSize, spx_word16_t);
+      /* Window for analysis */
+      /* FIXME: This is a kludge */
+      if (st->subframeSize==80)
+      {
+         for (i=0;i<st->windowSize;i++)
+            w_sig[i] = EXTRACT16(SHR32(MULT16_16(high[i],st->window[i>>1]),SIG_SHIFT));
+      } else {
+         for (i=0;i<st->windowSize;i++)
+            w_sig[i] = EXTRACT16(SHR32(MULT16_16(high[i],st->window[i]),SIG_SHIFT));
+      }
+      /* Compute auto-correlation */
+      _spx_autocorr(w_sig, autocorr, st->lpcSize+1, st->windowSize);
+      autocorr[0] = ADD16(autocorr[0],MULT16_16_Q15(autocorr[0],st->lpc_floor)); /* Noise floor in auto-correlation domain */
+
+      /* Lag windowing: equivalent to filtering in the power-spectrum domain */
+      for (i=0;i<st->lpcSize+1;i++)
+         autocorr[i] = MULT16_16_Q14(autocorr[i],st->lagWindow[i]);
+
+      /* Levinson-Durbin */
+      _spx_lpc(lpc, autocorr, st->lpcSize);
+   }
+
+   /* LPC to LSPs (x-domain) transform */
+   roots=lpc_to_lsp (lpc, st->lpcSize, lsp, 10, LSP_DELTA1, stack);
+   if (roots!=st->lpcSize)
+   {
+      roots = lpc_to_lsp (lpc, st->lpcSize, lsp, 10, LSP_DELTA2, stack);
+      if (roots!=st->lpcSize) {
+         /*If we can't find all LSP's, do some damage control and use a flat filter*/
+         for (i=0;i<st->lpcSize;i++)
+         {
+            lsp[i]=st->old_lsp[i];
+         }
+      }
+   }
+
+   /* VBR code */
+   if ((st->vbr_enabled || st->vad_enabled) && !dtx)
+   {
+      float ratio;
+      if (st->abr_enabled)
+      {
+         float qual_change=0;
+         if (st->abr_drift2 * st->abr_drift > 0)
+         {
+            /* Only adapt if long-term and short-term drift are the same sign */
+            qual_change = -.00001*st->abr_drift/(1+st->abr_count);
+            if (qual_change>.1)
+               qual_change=.1;
+            if (qual_change<-.1)
+               qual_change=-.1;
+         }
+         st->vbr_quality += qual_change;
+         if (st->vbr_quality>10)
+            st->vbr_quality=10;
+         if (st->vbr_quality<0)
+            st->vbr_quality=0;
+      }
+
+
+      ratio = 2*log((1.f+e_high)/(1.f+e_low));
+      
+      speex_encoder_ctl(st->st_low, SPEEX_GET_RELATIVE_QUALITY, &st->relative_quality);
+      if (ratio<-4)
+         ratio=-4;
+      if (ratio>2)
+         ratio=2;
+      /*if (ratio>-2)*/
+      if (st->vbr_enabled) 
+      {
+         spx_int32_t modeid;
+         modeid = mode->nb_modes-1;
+         st->relative_quality+=1.0*(ratio+2);
+	 if (st->relative_quality<-1)
+            st->relative_quality=-1;
+         while (modeid)
+         {
+            int v1;
+            float thresh;
+            v1=(int)floor(st->vbr_quality);
+            if (v1==10)
+               thresh = mode->vbr_thresh[modeid][v1];
+            else
+               thresh = (st->vbr_quality-v1)   * mode->vbr_thresh[modeid][v1+1] + 
+                        (1+v1-st->vbr_quality) * mode->vbr_thresh[modeid][v1];
+            if (st->relative_quality >= thresh && st->sampling_rate*st->submodes[modeid]->bits_per_frame/st->full_frame_size <= st->vbr_max_high)
+               break;
+            modeid--;
+         }
+         speex_encoder_ctl(state, SPEEX_SET_HIGH_MODE, &modeid);
+         if (st->abr_enabled)
+         {
+            spx_int32_t bitrate;
+            speex_encoder_ctl(state, SPEEX_GET_BITRATE, &bitrate);
+            st->abr_drift+=(bitrate-st->abr_enabled);
+            st->abr_drift2 = .95*st->abr_drift2 + .05*(bitrate-st->abr_enabled);
+            st->abr_count += 1.0;
+         }
+
+      } else {
+         /* VAD only */
+         int modeid;
+         if (st->relative_quality<2.0)
+            modeid=1;
+         else
+            modeid=st->submodeSelect;
+         /*speex_encoder_ctl(state, SPEEX_SET_MODE, &mode);*/
+         st->submodeID=modeid;
+
+      }
+      /*fprintf (stderr, "%f %f\n", ratio, low_qual);*/
+   }
+
+   if (st->encode_submode)
+   {
+      speex_bits_pack(bits, 1, 1);
+      if (dtx)
+         speex_bits_pack(bits, 0, SB_SUBMODE_BITS);
+      else
+         speex_bits_pack(bits, st->submodeID, SB_SUBMODE_BITS);
+   }
+
+   /* If null mode (no transmission), just set a couple things to zero*/
+   if (dtx || st->submodes[st->submodeID] == NULL)
+   {
+      for (i=0;i<st->frame_size;i++)
+         high[i]=VERY_SMALL;
+
+      for (i=0;i<st->lpcSize;i++)
+         st->mem_sw[i]=0;
+      st->first=1;
+
+      /* Final signal synthesis from excitation */
+      iir_mem16(high, st->interp_qlpc, high, st->frame_size, st->lpcSize, st->mem_sp, stack);
+
+      if (dtx)
+         return 0;
+      else
+         return 1;
+   }
+
+
+   /* LSP quantization */
+   SUBMODE(lsp_quant)(lsp, qlsp, st->lpcSize, bits);   
+
+   if (st->first)
+   {
+      for (i=0;i<st->lpcSize;i++)
+         st->old_lsp[i] = lsp[i];
+      for (i=0;i<st->lpcSize;i++)
+         st->old_qlsp[i] = qlsp[i];
+   }
+   
+   ALLOC(mem, st->lpcSize, spx_mem_t);
+   ALLOC(syn_resp, st->subframeSize, spx_word16_t);
+   ALLOC(innov, st->subframeSize, spx_sig_t);
+   ALLOC(target, st->subframeSize, spx_word16_t);
+
+   for (sub=0;sub<st->nbSubframes;sub++)
+   {
+      VARDECL(spx_word16_t *exc);
+      VARDECL(spx_word16_t *res);
+      VARDECL(spx_word16_t *sw);
+      spx_word16_t *sp;
+      spx_word16_t filter_ratio;     /*Q7*/
+      int offset;
+      spx_word32_t rl, rh;           /*Q13*/
+      spx_word16_t eh=0;
+
+      offset = st->subframeSize*sub;
+      sp=high+offset;
+      ALLOC(exc, st->subframeSize, spx_word16_t);
+      ALLOC(res, st->subframeSize, spx_word16_t);
+      ALLOC(sw, st->subframeSize, spx_word16_t);
+      
+      /* LSP interpolation (quantized and unquantized) */
+      lsp_interpolate(st->old_lsp, lsp, interp_lsp, st->lpcSize, sub, st->nbSubframes);
+      lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpcSize, sub, st->nbSubframes);
+
+      lsp_enforce_margin(interp_lsp, st->lpcSize, LSP_MARGIN);
+      lsp_enforce_margin(interp_qlsp, st->lpcSize, LSP_MARGIN);
+
+      lsp_to_lpc(interp_lsp, interp_lpc, st->lpcSize,stack);
+      lsp_to_lpc(interp_qlsp, st->interp_qlpc, st->lpcSize, stack);
+
+      bw_lpc(st->gamma1, interp_lpc, bw_lpc1, st->lpcSize);
+      bw_lpc(st->gamma2, interp_lpc, bw_lpc2, st->lpcSize);
+
+      /* Compute mid-band (4000 Hz for wideband) response of low-band and high-band
+         filters */
+      st->pi_gain[sub]=LPC_SCALING;
+      rh = LPC_SCALING;
+      for (i=0;i<st->lpcSize;i+=2)
+      {
+         rh += st->interp_qlpc[i+1] - st->interp_qlpc[i];
+         st->pi_gain[sub] += st->interp_qlpc[i] + st->interp_qlpc[i+1];
+      }
+      
+      rl = low_pi_gain[sub];
+#ifdef FIXED_POINT
+      filter_ratio=EXTRACT16(SATURATE(PDIV32(SHL32(ADD32(rl,82),7),ADD32(82,rh)),32767));
+#else
+      filter_ratio=(rl+.01)/(rh+.01);
+#endif
+      
+      /* Compute "real excitation" */
+      fir_mem16(sp, st->interp_qlpc, exc, st->subframeSize, st->lpcSize, st->mem_sp2, stack);
+      /* Compute energy of low-band and high-band excitation */
+
+      eh = compute_rms16(exc, st->subframeSize);
+
+      if (!SUBMODE(innovation_quant)) {/* 1 for spectral folding excitation, 0 for stochastic */
+         spx_word32_t g;   /*Q7*/
+         spx_word16_t el;  /*Q0*/
+         el = low_innov_rms[sub];
+
+         /* Gain to use if we want to use the low-band excitation for high-band */
+         g=PDIV32(MULT16_16(filter_ratio,eh),EXTEND32(ADD16(1,el)));
+         
+#if 0
+         {
+            char *tmp_stack=stack;
+            float *tmp_sig;
+            float g2;
+            ALLOC(tmp_sig, st->subframeSize, spx_sig_t);
+            for (i=0;i<st->lpcSize;i++)
+               mem[i]=st->mem_sp[i];
+            iir_mem2(st->low_innov+offset, st->interp_qlpc, tmp_sig, st->subframeSize, st->lpcSize, mem);
+            g2 = compute_rms(sp, st->subframeSize)/(.01+compute_rms(tmp_sig, st->subframeSize));
+            /*fprintf (stderr, "gains: %f %f\n", g, g2);*/
+            g = g2;
+            stack = tmp_stack;
+         }
+#endif
+
+         /*print_vec(&g, 1, "gain factor");*/
+         /* Gain quantization */
+         {
+            int quant = scal_quant(g, fold_quant_bound, 32);
+            /*speex_warning_int("tata", quant);*/
+            if (quant<0)
+               quant=0;
+            if (quant>31)
+               quant=31;
+            speex_bits_pack(bits, quant, 5);
+         }
+         if (st->innov_rms_save)
+         {
+            st->innov_rms_save[sub] = eh;
+         }
+         st->exc_rms[sub] = eh;
+      } else {
+         spx_word16_t gc;       /*Q7*/
+         spx_word32_t scale;    /*Q14*/
+         spx_word16_t el;       /*Q0*/
+         el = low_exc_rms[sub]; /*Q0*/
+
+         gc = PDIV32_16(MULT16_16(filter_ratio,1+eh),1+el);
+
+         /* This is a kludge that cleans up a historical bug */
+         if (st->subframeSize==80)
+            gc = MULT16_16_P15(QCONST16(0.70711f,15),gc);
+         /*printf ("%f %f %f %f\n", el, eh, filter_ratio, gc);*/
+         {
+            int qgc = scal_quant(gc, gc_quant_bound, 16);
+            speex_bits_pack(bits, qgc, 4);
+            gc = MULT16_16_Q15(QCONST16(0.87360,15),gc_quant_bound[qgc]);
+         }
+         if (st->subframeSize==80)
+            gc = MULT16_16_P14(QCONST16(1.4142f,14), gc);
+
+         scale = SHL32(MULT16_16(PDIV32_16(SHL32(EXTEND32(gc),SIG_SHIFT-6),filter_ratio),(1+el)),6);
+
+         compute_impulse_response(st->interp_qlpc, bw_lpc1, bw_lpc2, syn_resp, st->subframeSize, st->lpcSize, stack);
+
+         
+         /* Reset excitation */
+         for (i=0;i<st->subframeSize;i++)
+            res[i]=VERY_SMALL;
+         
+         /* Compute zero response (ringing) of A(z/g1) / ( A(z/g2) * Aq(z) ) */
+         for (i=0;i<st->lpcSize;i++)
+            mem[i]=st->mem_sp[i];
+         iir_mem16(res, st->interp_qlpc, res, st->subframeSize, st->lpcSize, mem, stack);
+
+         for (i=0;i<st->lpcSize;i++)
+            mem[i]=st->mem_sw[i];
+         filter_mem16(res, bw_lpc1, bw_lpc2, res, st->subframeSize, st->lpcSize, mem, stack);
+
+         /* Compute weighted signal */
+         for (i=0;i<st->lpcSize;i++)
+            mem[i]=st->mem_sw[i];
+         filter_mem16(sp, bw_lpc1, bw_lpc2, sw, st->subframeSize, st->lpcSize, mem, stack);
+
+         /* Compute target signal */
+         for (i=0;i<st->subframeSize;i++)
+            target[i]=SUB16(sw[i],res[i]);
+
+         signal_div(target, target, scale, st->subframeSize);
+
+         /* Reset excitation */
+         for (i=0;i<st->subframeSize;i++)
+            innov[i]=0;
+
+         /*print_vec(target, st->subframeSize, "\ntarget");*/
+         SUBMODE(innovation_quant)(target, st->interp_qlpc, bw_lpc1, bw_lpc2, 
+                                   SUBMODE(innovation_params), st->lpcSize, st->subframeSize, 
+                                   innov, syn_resp, bits, stack, st->complexity, SUBMODE(double_codebook));
+         /*print_vec(target, st->subframeSize, "after");*/
+
+         signal_mul(innov, innov, scale, st->subframeSize);
+
+         if (SUBMODE(double_codebook)) {
+            char *tmp_stack=stack;
+            VARDECL(spx_sig_t *innov2);
+            ALLOC(innov2, st->subframeSize, spx_sig_t);
+            for (i=0;i<st->subframeSize;i++)
+               innov2[i]=0;
+            for (i=0;i<st->subframeSize;i++)
+               target[i]=MULT16_16_P13(QCONST16(2.5f,13), target[i]);
+
+            SUBMODE(innovation_quant)(target, st->interp_qlpc, bw_lpc1, bw_lpc2, 
+                                      SUBMODE(innovation_params), st->lpcSize, st->subframeSize, 
+                                      innov2, syn_resp, bits, stack, st->complexity, 0);
+            signal_mul(innov2, innov2, MULT16_32_P15(QCONST16(0.4f,15),scale), st->subframeSize);
+
+            for (i=0;i<st->subframeSize;i++)
+               innov[i] = ADD32(innov[i],innov2[i]);
+            stack = tmp_stack;
+         }
+         for (i=0;i<st->subframeSize;i++)
+            exc[i] = PSHR32(innov[i],SIG_SHIFT);
+
+         if (st->innov_rms_save)
+         {
+            st->innov_rms_save[sub] = MULT16_16_Q15(QCONST16(.70711f, 15), compute_rms(innov, st->subframeSize));
+         }
+         st->exc_rms[sub] = compute_rms16(exc, st->subframeSize);
+         
+
+      }
+
+      
+      /*Keep the previous memory*/
+      for (i=0;i<st->lpcSize;i++)
+         mem[i]=st->mem_sp[i];
+      /* Final signal synthesis from excitation */
+      iir_mem16(exc, st->interp_qlpc, sp, st->subframeSize, st->lpcSize, st->mem_sp, stack);
+      
+      /* Compute weighted signal again, from synthesized speech (not sure it's the right thing) */
+      filter_mem16(sp, bw_lpc1, bw_lpc2, sw, st->subframeSize, st->lpcSize, st->mem_sw, stack);
+   }
+
+   for (i=0;i<st->lpcSize;i++)
+      st->old_lsp[i] = lsp[i];
+   for (i=0;i<st->lpcSize;i++)
+      st->old_qlsp[i] = qlsp[i];
+
+   st->first=0;
+
+   return 1;
+}
+
+
+
+
+
+void *sb_decoder_init(const SpeexMode *m)
+{
+   spx_int32_t tmp;
+   SBDecState *st;
+   const SpeexSBMode *mode;
+   st = (SBDecState*)speex_alloc(sizeof(SBDecState));
+   if (!st)
+      return NULL;
+   st->mode = m;
+   mode=(const SpeexSBMode*)m->mode;
+   st->encode_submode = 1;
+
+   st->st_low = speex_decoder_init(mode->nb_mode);
+#if defined(VAR_ARRAYS) || defined (USE_ALLOCA)
+   st->stack = NULL;
+#else
+   /*st->stack = (char*)speex_alloc_scratch(SB_DEC_STACK);*/
+   speex_decoder_ctl(st->st_low, SPEEX_GET_STACK, &st->stack);
+#endif
+
+   st->full_frame_size = 2*mode->frameSize;
+   st->frame_size = mode->frameSize;
+   st->subframeSize = mode->subframeSize;
+   st->nbSubframes = mode->frameSize/mode->subframeSize;
+   st->lpcSize=mode->lpcSize;
+   speex_decoder_ctl(st->st_low, SPEEX_GET_SAMPLING_RATE, &st->sampling_rate);
+   st->sampling_rate*=2;
+   tmp=1;
+   speex_decoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, &tmp);
+
+   st->submodes=mode->submodes;
+   st->submodeID=mode->defaultSubmode;
+
+   st->first=1;
+
+   st->g0_mem = (spx_word32_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word32_t));
+   st->g1_mem = (spx_word32_t*)speex_alloc((QMF_ORDER)*sizeof(spx_word32_t));
+
+   st->excBuf = (spx_word16_t*)speex_alloc((st->subframeSize)*sizeof(spx_word16_t));
+
+   st->old_qlsp = (spx_lsp_t*)speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
+   st->interp_qlpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t));
+
+   st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t));
+   st->exc_rms = (spx_word16_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word16_t));
+   st->mem_sp = (spx_mem_t*)speex_alloc((2*st->lpcSize)*sizeof(spx_mem_t));
+   
+   st->innov_save = NULL;
+
+
+   st->lpc_enh_enabled=0;
+   st->seed = 1000;
+
+#ifdef ENABLE_VALGRIND
+   VALGRIND_MAKE_READABLE(st, (st->stack-(char*)st));
+#endif
+   return st;
+}
+
+void sb_decoder_destroy(void *state)
+{
+   SBDecState *st;
+   st = (SBDecState*)state;
+   speex_decoder_destroy(st->st_low);
+#if !(defined(VAR_ARRAYS) || defined (USE_ALLOCA))
+   /*speex_free_scratch(st->stack);*/
+#endif
+
+   speex_free(st->g0_mem);
+   speex_free(st->g1_mem);
+   speex_free(st->excBuf);
+   speex_free(st->old_qlsp);
+   speex_free(st->interp_qlpc);
+   speex_free(st->pi_gain);
+   speex_free(st->exc_rms);
+   speex_free(st->mem_sp);
+
+   speex_free(state);
+}
+
+static void sb_decode_lost(SBDecState *st, spx_word16_t *out, int dtx, char *stack)
+{
+   int i;
+   int saved_modeid=0;
+
+   if (dtx)
+   {
+      saved_modeid=st->submodeID;
+      st->submodeID=1;
+   } else {
+      bw_lpc(QCONST16(0.99f,15), st->interp_qlpc, st->interp_qlpc, st->lpcSize);
+   }
+
+   st->first=1;
+   
+   
+   /* Final signal synthesis from excitation */
+   if (!dtx)
+   {
+      st->last_ener =  MULT16_16_Q15(QCONST16(.9f,15),st->last_ener);
+   }
+   for (i=0;i<st->frame_size;i++)
+      out[i+st->frame_size] = speex_rand(st->last_ener, &st->seed);
+
+   iir_mem16(out+st->frame_size, st->interp_qlpc, out+st->frame_size, st->frame_size, st->lpcSize, 
+            st->mem_sp, stack);
+   
+   
+   /* Reconstruct the original */
+   qmf_synth(out, out+st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem, stack);
+   if (dtx)
+   {
+      st->submodeID=saved_modeid;
+   }
+
+   return;
+}
+
+int sb_decode(void *state, SpeexBits *bits, void *vout)
+{
+   int i, sub;
+   SBDecState *st;
+   int wideband;
+   int ret;
+   char *stack;
+   VARDECL(spx_word32_t *low_pi_gain);
+   VARDECL(spx_word16_t *low_exc_rms);
+   VARDECL(spx_coef_t *ak);
+   VARDECL(spx_lsp_t *qlsp);
+   VARDECL(spx_lsp_t *interp_qlsp);
+   spx_int32_t dtx;
+   const SpeexSBMode *mode;
+   spx_word16_t *out = (spx_word16_t*)vout;
+   spx_word16_t *low_innov_alias;
+   spx_word32_t exc_ener_sum = 0;
+   
+   st = (SBDecState*)state;
+   stack=st->stack;
+   mode = (const SpeexSBMode*)(st->mode->mode);
+
+   low_innov_alias = out+st->frame_size;
+   speex_decoder_ctl(st->st_low, SPEEX_SET_INNOVATION_SAVE, low_innov_alias);
+   /* Decode the low-band */
+   ret = speex_decode_native(st->st_low, bits, out);
+
+   speex_decoder_ctl(st->st_low, SPEEX_GET_DTX_STATUS, &dtx);
+
+   /* If error decoding the narrowband part, propagate error */
+   if (ret!=0)
+   {
+      return ret;
+   }
+
+   if (!bits)
+   {
+      sb_decode_lost(st, out, dtx, stack);
+      return 0;
+   }
+
+   if (st->encode_submode)
+   {
+
+      /*Check "wideband bit"*/
+      if (speex_bits_remaining(bits)>0)
+         wideband = speex_bits_peek(bits);
+      else
+         wideband = 0;
+      if (wideband)
+      {
+         /*Regular wideband frame, read the submode*/
+         wideband = speex_bits_unpack_unsigned(bits, 1);
+         st->submodeID = speex_bits_unpack_unsigned(bits, SB_SUBMODE_BITS);
+      } else
+      {
+         /*Was a narrowband frame, set "null submode"*/
+         st->submodeID = 0;
+      }
+      if (st->submodeID != 0 && st->submodes[st->submodeID] == NULL)
+      {
+         speex_notify("Invalid mode encountered. The stream is corrupted.");
+         return -2;
+      }
+   }
+
+   /* If null mode (no transmission), just set a couple things to zero*/
+   if (st->submodes[st->submodeID] == NULL)
+   {
+      if (dtx)
+      {
+         sb_decode_lost(st, out, 1, stack);
+         return 0;
+      }
+
+      for (i=0;i<st->frame_size;i++)
+         out[st->frame_size+i]=VERY_SMALL;
+
+      st->first=1;
+
+      /* Final signal synthesis from excitation */
+      iir_mem16(out+st->frame_size, st->interp_qlpc, out+st->frame_size, st->frame_size, st->lpcSize, st->mem_sp, stack);
+
+      qmf_synth(out, out+st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem, stack);
+
+      return 0;
+
+   }
+
+   ALLOC(low_pi_gain, st->nbSubframes, spx_word32_t);
+   ALLOC(low_exc_rms, st->nbSubframes, spx_word16_t);
+   speex_decoder_ctl(st->st_low, SPEEX_GET_PI_GAIN, low_pi_gain);
+   speex_decoder_ctl(st->st_low, SPEEX_GET_EXC, low_exc_rms);
+
+   ALLOC(qlsp, st->lpcSize, spx_lsp_t);
+   ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t);
+   SUBMODE(lsp_unquant)(qlsp, st->lpcSize, bits);
+   
+   if (st->first)
+   {
+      for (i=0;i<st->lpcSize;i++)
+         st->old_qlsp[i] = qlsp[i];
+   }
+   
+   ALLOC(ak, st->lpcSize, spx_coef_t);
+
+   for (sub=0;sub<st->nbSubframes;sub++)
+   {
+      VARDECL(spx_word32_t *exc);
+      spx_word16_t *innov_save=NULL;
+      spx_word16_t *sp;
+      spx_word16_t filter_ratio;
+      spx_word16_t el=0;
+      int offset;
+      spx_word32_t rl=0,rh=0;
+      
+      offset = st->subframeSize*sub;
+      sp=out+st->frame_size+offset;
+      ALLOC(exc, st->subframeSize, spx_word32_t);
+      /* Pointer for saving innovation */
+      if (st->innov_save)
+      {
+         innov_save = st->innov_save+2*offset;
+         for (i=0;i<2*st->subframeSize;i++)
+            innov_save[i]=0;
+      }
+      
+      /* LSP interpolation */
+      lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpcSize, sub, st->nbSubframes);
+
+      lsp_enforce_margin(interp_qlsp, st->lpcSize, LSP_MARGIN);
+
+      /* LSP to LPC */
+      lsp_to_lpc(interp_qlsp, ak, st->lpcSize, stack);
+
+      /* Calculate reponse ratio between the low and high filter in the middle
+         of the band (4000 Hz) */
+      
+         st->pi_gain[sub]=LPC_SCALING;
+         rh = LPC_SCALING;
+         for (i=0;i<st->lpcSize;i+=2)
+         {
+            rh += ak[i+1] - ak[i];
+            st->pi_gain[sub] += ak[i] + ak[i+1];
+         }
+
+         rl = low_pi_gain[sub];
+#ifdef FIXED_POINT
+         filter_ratio=EXTRACT16(SATURATE(PDIV32(SHL32(ADD32(rl,82),7),ADD32(82,rh)),32767));
+#else
+         filter_ratio=(rl+.01)/(rh+.01);
+#endif
+      
+      for (i=0;i<st->subframeSize;i++)
+         exc[i]=0;
+      if (!SUBMODE(innovation_unquant))
+      {
+         spx_word32_t g;
+         int quant;
+
+         quant = speex_bits_unpack_unsigned(bits, 5);
+         g= spx_exp(MULT16_16(QCONST16(.125f,11),(quant-10)));
+         
+         g = PDIV32(g, filter_ratio);
+         
+         for (i=0;i<st->subframeSize;i+=2)
+         {
+            exc[i]=SHL32(MULT16_32_P15(MULT16_16_Q15(mode->folding_gain,low_innov_alias[offset+i]),SHL32(g,6)),SIG_SHIFT);
+            exc[i+1]=NEG32(SHL32(MULT16_32_P15(MULT16_16_Q15(mode->folding_gain,low_innov_alias[offset+i+1]),SHL32(g,6)),SIG_SHIFT));
+         }
+         
+      } else {
+         spx_word16_t gc;
+         spx_word32_t scale;
+         int qgc = speex_bits_unpack_unsigned(bits, 4);
+         
+         el = low_exc_rms[sub];
+         gc = MULT16_16_Q15(QCONST16(0.87360,15),gc_quant_bound[qgc]);
+
+         if (st->subframeSize==80)
+            gc = MULT16_16_P14(QCONST16(1.4142f,14),gc);
+
+         scale = SHL32(PDIV32(SHL32(MULT16_16(gc, el),3), filter_ratio),SIG_SHIFT-3);
+         SUBMODE(innovation_unquant)(exc, SUBMODE(innovation_params), st->subframeSize, 
+                                     bits, stack, &st->seed);
+
+         signal_mul(exc,exc,scale,st->subframeSize);
+
+         if (SUBMODE(double_codebook)) {
+            char *tmp_stack=stack;
+            VARDECL(spx_sig_t *innov2);
+            ALLOC(innov2, st->subframeSize, spx_sig_t);
+            for (i=0;i<st->subframeSize;i++)
+               innov2[i]=0;
+            SUBMODE(innovation_unquant)(innov2, SUBMODE(innovation_params), st->subframeSize, 
+                                        bits, stack, &st->seed);
+            signal_mul(innov2, innov2, MULT16_32_P15(QCONST16(0.4f,15),scale), st->subframeSize);
+            for (i=0;i<st->subframeSize;i++)
+               exc[i] = ADD32(exc[i],innov2[i]);
+            stack = tmp_stack;
+         }
+
+      }
+      
+      if (st->innov_save)
+      {
+         for (i=0;i<st->subframeSize;i++)
+            innov_save[2*i]=EXTRACT16(PSHR32(exc[i],SIG_SHIFT));
+      }
+      
+      for (i=0;i<st->subframeSize;i++)
+         sp[i]=st->excBuf[i];
+      iir_mem16(sp, st->interp_qlpc, sp, st->subframeSize, st->lpcSize, 
+               st->mem_sp, stack);
+      for (i=0;i<st->subframeSize;i++)
+         st->excBuf[i]=EXTRACT16(PSHR32(exc[i],SIG_SHIFT));
+      for (i=0;i<st->lpcSize;i++)
+         st->interp_qlpc[i] = ak[i];
+      st->exc_rms[sub] = compute_rms16(st->excBuf, st->subframeSize);
+      exc_ener_sum = ADD32(exc_ener_sum, DIV32(MULT16_16(st->exc_rms[sub],st->exc_rms[sub]), st->nbSubframes));
+   }
+   st->last_ener = spx_sqrt(exc_ener_sum);
+   
+   qmf_synth(out, out+st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem, stack);
+   for (i=0;i<st->lpcSize;i++)
+      st->old_qlsp[i] = qlsp[i];
+
+   st->first=0;
+
+   return 0;
+}
+
+
+int sb_encoder_ctl(void *state, int request, void *ptr)
+{
+   SBEncState *st;
+   st=(SBEncState*)state;
+   switch(request)
+   {
+   case SPEEX_GET_FRAME_SIZE:
+      (*(spx_int32_t*)ptr) = st->full_frame_size;
+      break;
+   case SPEEX_SET_HIGH_MODE:
+      st->submodeSelect = st->submodeID = (*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_SET_LOW_MODE:
+      speex_encoder_ctl(st->st_low, SPEEX_SET_LOW_MODE, ptr);
+      break;
+   case SPEEX_SET_DTX:
+      speex_encoder_ctl(st->st_low, SPEEX_SET_DTX, ptr);
+      break;
+   case SPEEX_GET_DTX:
+      speex_encoder_ctl(st->st_low, SPEEX_GET_DTX, ptr);
+      break;
+   case SPEEX_GET_LOW_MODE:
+      speex_encoder_ctl(st->st_low, SPEEX_GET_LOW_MODE, ptr);
+      break;
+   case SPEEX_SET_MODE:
+      speex_encoder_ctl(st, SPEEX_SET_QUALITY, ptr);
+      break;
+   case SPEEX_SET_VBR:
+      st->vbr_enabled = (*(spx_int32_t*)ptr);
+      speex_encoder_ctl(st->st_low, SPEEX_SET_VBR, ptr);
+      break;
+   case SPEEX_GET_VBR:
+      (*(spx_int32_t*)ptr) = st->vbr_enabled;
+      break;
+   case SPEEX_SET_VAD:
+      st->vad_enabled = (*(spx_int32_t*)ptr);
+      speex_encoder_ctl(st->st_low, SPEEX_SET_VAD, ptr);
+      break;
+   case SPEEX_GET_VAD:
+      (*(spx_int32_t*)ptr) = st->vad_enabled;
+      break;
+   case SPEEX_SET_VBR_QUALITY:
+      {
+         spx_int32_t q;
+         float qual = (*(float*)ptr)+.6;
+         st->vbr_quality = (*(float*)ptr);
+         if (qual>10)
+            qual=10;
+         q=(int)floor(.5+*(float*)ptr);
+         if (q>10)
+            q=10;
+         speex_encoder_ctl(st->st_low, SPEEX_SET_VBR_QUALITY, &qual);
+         speex_encoder_ctl(state, SPEEX_SET_QUALITY, &q);
+         break;
+      }
+   case SPEEX_GET_VBR_QUALITY:
+      (*(float*)ptr) = st->vbr_quality;
+      break;
+   case SPEEX_SET_ABR:
+      st->abr_enabled = (*(spx_int32_t*)ptr);
+      st->vbr_enabled = st->abr_enabled!=0;
+      speex_encoder_ctl(st->st_low, SPEEX_SET_VBR, &st->vbr_enabled);
+      if (st->vbr_enabled) 
+      {
+         spx_int32_t i=10, rate, target;
+         float vbr_qual;
+         target = (*(spx_int32_t*)ptr);
+         while (i>=0)
+         {
+            speex_encoder_ctl(st, SPEEX_SET_QUALITY, &i);
+            speex_encoder_ctl(st, SPEEX_GET_BITRATE, &rate);
+            if (rate <= target)
+               break;
+            i--;
+         }
+         vbr_qual=i;
+         if (vbr_qual<0)
+            vbr_qual=0;
+         speex_encoder_ctl(st, SPEEX_SET_VBR_QUALITY, &vbr_qual);
+         st->abr_count=0;
+         st->abr_drift=0;
+         st->abr_drift2=0;
+      }
+      
+      break;
+   case SPEEX_GET_ABR:
+      (*(spx_int32_t*)ptr) = st->abr_enabled;
+      break;
+   case SPEEX_SET_QUALITY:
+      {
+         spx_int32_t nb_qual;
+         int quality = (*(spx_int32_t*)ptr);
+         if (quality < 0)
+            quality = 0;
+         if (quality > 10)
+            quality = 10;
+         st->submodeSelect = st->submodeID = ((const SpeexSBMode*)(st->mode->mode))->quality_map[quality];
+         nb_qual = ((const SpeexSBMode*)(st->mode->mode))->low_quality_map[quality];
+         speex_encoder_ctl(st->st_low, SPEEX_SET_MODE, &nb_qual);
+      }
+      break;
+   case SPEEX_SET_COMPLEXITY:
+      speex_encoder_ctl(st->st_low, SPEEX_SET_COMPLEXITY, ptr);
+      st->complexity = (*(spx_int32_t*)ptr);
+      if (st->complexity<1)
+         st->complexity=1;
+      break;
+   case SPEEX_GET_COMPLEXITY:
+      (*(spx_int32_t*)ptr) = st->complexity;
+      break;
+   case SPEEX_SET_BITRATE:
+      {
+         spx_int32_t i=10;
+         spx_int32_t rate, target;
+         target = (*(spx_int32_t*)ptr);
+         while (i>=0)
+         {
+            speex_encoder_ctl(st, SPEEX_SET_QUALITY, &i);
+            speex_encoder_ctl(st, SPEEX_GET_BITRATE, &rate);
+            if (rate <= target)
+               break;
+            i--;
+         }
+      }
+      break;
+   case SPEEX_GET_BITRATE:
+      speex_encoder_ctl(st->st_low, request, ptr);
+      /*fprintf (stderr, "before: %d\n", (*(int*)ptr));*/
+      if (st->submodes[st->submodeID])
+         (*(spx_int32_t*)ptr) += st->sampling_rate*SUBMODE(bits_per_frame)/st->full_frame_size;
+      else
+         (*(spx_int32_t*)ptr) += st->sampling_rate*(SB_SUBMODE_BITS+1)/st->full_frame_size;
+      /*fprintf (stderr, "after: %d\n", (*(int*)ptr));*/
+      break;
+   case SPEEX_SET_SAMPLING_RATE:
+      {
+         spx_int32_t tmp=(*(spx_int32_t*)ptr);
+         st->sampling_rate = tmp;
+         tmp>>=1;
+         speex_encoder_ctl(st->st_low, SPEEX_SET_SAMPLING_RATE, &tmp);
+      }
+      break;
+   case SPEEX_GET_SAMPLING_RATE:
+      (*(spx_int32_t*)ptr)=st->sampling_rate;
+      break;
+   case SPEEX_RESET_STATE:
+      {
+         int i;
+         st->first = 1;
+         for (i=0;i<st->lpcSize;i++)
+            st->old_lsp[i]=(M_PI*((float)(i+1)))/(st->lpcSize+1);
+         for (i=0;i<st->lpcSize;i++)
+            st->mem_sw[i]=st->mem_sp[i]=st->mem_sp2[i]=0;
+         for (i=0;i<QMF_ORDER;i++)
+            st->h0_mem[i]=st->h1_mem[i]=0;
+      }
+      break;
+   case SPEEX_SET_SUBMODE_ENCODING:
+      st->encode_submode = (*(spx_int32_t*)ptr);
+      speex_encoder_ctl(st->st_low, SPEEX_SET_SUBMODE_ENCODING, ptr);
+      break;
+   case SPEEX_GET_SUBMODE_ENCODING:
+      (*(spx_int32_t*)ptr) = st->encode_submode;
+      break;
+   case SPEEX_GET_LOOKAHEAD:
+      speex_encoder_ctl(st->st_low, SPEEX_GET_LOOKAHEAD, ptr);
+      (*(spx_int32_t*)ptr) = 2*(*(spx_int32_t*)ptr) + QMF_ORDER - 1;
+      break;
+   case SPEEX_SET_PLC_TUNING:
+      speex_encoder_ctl(st->st_low, SPEEX_SET_PLC_TUNING, ptr);
+      break;
+   case SPEEX_GET_PLC_TUNING:
+      speex_encoder_ctl(st->st_low, SPEEX_GET_PLC_TUNING, ptr);
+      break;
+   case SPEEX_SET_VBR_MAX_BITRATE:
+      {
+         st->vbr_max = (*(spx_int32_t*)ptr);
+         if (SPEEX_SET_VBR_MAX_BITRATE<1)
+         {
+            speex_encoder_ctl(st->st_low, SPEEX_SET_VBR_MAX_BITRATE, &st->vbr_max);
+            st->vbr_max_high = 17600;
+         } else {
+            spx_int32_t low_rate;
+            if (st->vbr_max >= 42200)
+            {
+               st->vbr_max_high = 17600;
+            } else if (st->vbr_max >= 27800)
+            {
+               st->vbr_max_high = 9600;
+            } else if (st->vbr_max > 20600)
+            {
+               st->vbr_max_high = 5600;
+            } else {
+               st->vbr_max_high = 1800;
+            }
+            if (st->subframeSize==80)
+               st->vbr_max_high = 1800;
+            low_rate = st->vbr_max - st->vbr_max_high;
+            speex_encoder_ctl(st->st_low, SPEEX_SET_VBR_MAX_BITRATE, &low_rate);
+         }
+      }
+      break;
+   case SPEEX_GET_VBR_MAX_BITRATE:
+      (*(spx_int32_t*)ptr) = st->vbr_max;
+      break;
+   case SPEEX_SET_HIGHPASS:
+      speex_encoder_ctl(st->st_low, SPEEX_SET_HIGHPASS, ptr);
+      break;
+   case SPEEX_GET_HIGHPASS:
+      speex_encoder_ctl(st->st_low, SPEEX_GET_HIGHPASS, ptr);
+      break;
+
+
+   /* This is all internal stuff past this point */
+   case SPEEX_GET_PI_GAIN:
+      {
+         int i;
+         spx_word32_t *g = (spx_word32_t*)ptr;
+         for (i=0;i<st->nbSubframes;i++)
+            g[i]=st->pi_gain[i];
+      }
+      break;
+   case SPEEX_GET_EXC:
+      {
+         int i;
+         for (i=0;i<st->nbSubframes;i++)
+            ((spx_word16_t*)ptr)[i] = st->exc_rms[i];
+      }
+      break;
+   case SPEEX_GET_RELATIVE_QUALITY:
+      (*(float*)ptr)=st->relative_quality;
+      break;
+   case SPEEX_SET_INNOVATION_SAVE:
+      st->innov_rms_save = (spx_word16_t*)ptr;
+      break;
+   case SPEEX_SET_WIDEBAND:
+      speex_encoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, ptr);
+      break;
+   case SPEEX_GET_STACK:
+      *((char**)ptr) = st->stack;
+      break;
+   default:
+      speex_warning_int("Unknown nb_ctl request: ", request);
+      return -1;
+   }
+   return 0;
+}
+
+int sb_decoder_ctl(void *state, int request, void *ptr)
+{
+   SBDecState *st;
+   st=(SBDecState*)state;
+   switch(request)
+   {
+   case SPEEX_SET_HIGH_MODE:
+      st->submodeID = (*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_SET_LOW_MODE:
+      speex_decoder_ctl(st->st_low, SPEEX_SET_LOW_MODE, ptr);
+      break;
+   case SPEEX_GET_LOW_MODE:
+      speex_decoder_ctl(st->st_low, SPEEX_GET_LOW_MODE, ptr);
+      break;
+   case SPEEX_GET_FRAME_SIZE:
+      (*(spx_int32_t*)ptr) = st->full_frame_size;
+      break;
+   case SPEEX_SET_ENH:
+      speex_decoder_ctl(st->st_low, request, ptr);
+      st->lpc_enh_enabled = *((spx_int32_t*)ptr);
+      break;
+   case SPEEX_GET_ENH:
+      *((spx_int32_t*)ptr) = st->lpc_enh_enabled;
+      break;
+   case SPEEX_SET_MODE:
+   case SPEEX_SET_QUALITY:
+      {
+         spx_int32_t nb_qual;
+         int quality = (*(spx_int32_t*)ptr);
+         if (quality < 0)
+            quality = 0;
+         if (quality > 10)
+            quality = 10;
+         st->submodeID = ((const SpeexSBMode*)(st->mode->mode))->quality_map[quality];
+         nb_qual = ((const SpeexSBMode*)(st->mode->mode))->low_quality_map[quality];
+         speex_decoder_ctl(st->st_low, SPEEX_SET_MODE, &nb_qual);
+      }
+      break;
+   case SPEEX_GET_BITRATE:
+      speex_decoder_ctl(st->st_low, request, ptr);
+      if (st->submodes[st->submodeID])
+         (*(spx_int32_t*)ptr) += st->sampling_rate*SUBMODE(bits_per_frame)/st->full_frame_size;
+      else
+         (*(spx_int32_t*)ptr) += st->sampling_rate*(SB_SUBMODE_BITS+1)/st->full_frame_size;
+      break;
+   case SPEEX_SET_SAMPLING_RATE:
+      {
+         spx_int32_t tmp=(*(spx_int32_t*)ptr);
+         st->sampling_rate = tmp;
+         tmp>>=1;
+         speex_decoder_ctl(st->st_low, SPEEX_SET_SAMPLING_RATE, &tmp);
+      }
+      break;
+   case SPEEX_GET_SAMPLING_RATE:
+      (*(spx_int32_t*)ptr)=st->sampling_rate;
+      break;
+   case SPEEX_SET_HANDLER:
+      speex_decoder_ctl(st->st_low, SPEEX_SET_HANDLER, ptr);
+      break;
+   case SPEEX_SET_USER_HANDLER:
+      speex_decoder_ctl(st->st_low, SPEEX_SET_USER_HANDLER, ptr);
+      break;
+   case SPEEX_RESET_STATE:
+      {
+         int i;
+         for (i=0;i<2*st->lpcSize;i++)
+            st->mem_sp[i]=0;
+         for (i=0;i<QMF_ORDER;i++)
+            st->g0_mem[i]=st->g1_mem[i]=0;
+         st->last_ener=0;
+      }
+      break;
+   case SPEEX_SET_SUBMODE_ENCODING:
+      st->encode_submode = (*(spx_int32_t*)ptr);
+      speex_decoder_ctl(st->st_low, SPEEX_SET_SUBMODE_ENCODING, ptr);
+      break;
+   case SPEEX_GET_SUBMODE_ENCODING:
+      (*(spx_int32_t*)ptr) = st->encode_submode;
+      break;
+   case SPEEX_GET_LOOKAHEAD:
+      speex_decoder_ctl(st->st_low, SPEEX_GET_LOOKAHEAD, ptr);
+      (*(spx_int32_t*)ptr) = 2*(*(spx_int32_t*)ptr);
+      break;
+   case SPEEX_SET_HIGHPASS:
+      speex_decoder_ctl(st->st_low, SPEEX_SET_HIGHPASS, ptr);
+      break;
+   case SPEEX_GET_HIGHPASS:
+      speex_decoder_ctl(st->st_low, SPEEX_GET_HIGHPASS, ptr);
+      break;
+
+   case SPEEX_GET_PI_GAIN:
+      {
+         int i;
+         spx_word32_t *g = (spx_word32_t*)ptr;
+         for (i=0;i<st->nbSubframes;i++)
+            g[i]=st->pi_gain[i];
+      }
+      break;
+   case SPEEX_GET_EXC:
+      {
+         int i;
+         for (i=0;i<st->nbSubframes;i++)
+            ((spx_word16_t*)ptr)[i] = st->exc_rms[i];
+      }
+      break;
+   case SPEEX_GET_DTX_STATUS:
+      speex_decoder_ctl(st->st_low, SPEEX_GET_DTX_STATUS, ptr);
+      break;
+   case SPEEX_SET_INNOVATION_SAVE:
+      st->innov_save = (spx_word16_t*)ptr;
+      break;
+   case SPEEX_SET_WIDEBAND:
+      speex_decoder_ctl(st->st_low, SPEEX_SET_WIDEBAND, ptr);
+      break;
+   case SPEEX_GET_STACK:
+      *((char**)ptr) = st->stack;
+      break;
+   default:
+      speex_warning_int("Unknown nb_ctl request: ", request);
+      return -1;
+   }
+   return 0;
+}
+
+#endif
+
diff --git a/3rdparty/speex/libspeex/sb_celp.h b/3rdparty/speex/libspeex/sb_celp.h
new file mode 100644
index 0000000..a0dc3af
--- /dev/null
+++ b/3rdparty/speex/libspeex/sb_celp.h
@@ -0,0 +1,155 @@
+/* Copyright (C) 2002-2006 Jean-Marc Valin */
+/**
+   @file sb_celp.h
+   @brief Sub-band CELP mode used for wideband encoding
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef SB_CELP_H
+#define SB_CELP_H
+
+#include "modes.h"
+#include <speex/speex_bits.h>
+#include "nb_celp.h"
+
+/**Structure representing the full state of the sub-band encoder*/
+typedef struct SBEncState {
+   const SpeexMode *mode;         /**< Pointer to the mode (containing for vtable info) */
+   void *st_low;                  /**< State of the low-band (narrowband) encoder */
+   int    full_frame_size;        /**< Length of full-band frames*/
+   int    frame_size;             /**< Length of high-band frames*/
+   int    subframeSize;           /**< Length of high-band sub-frames*/
+   int    nbSubframes;            /**< Number of high-band sub-frames*/
+   int    windowSize;             /**< Length of high-band LPC window*/
+   int    lpcSize;                /**< Order of high-band LPC analysis */
+   int    bufSize;                /**< Buffer size */
+   int    first;                  /**< First frame? */
+   float  lag_factor;             /**< Lag-windowing control parameter */
+   spx_word16_t  lpc_floor;       /**< Controls LPC analysis noise floor */
+   spx_word16_t  gamma1;          /**< Perceptual weighting coef 1 */
+   spx_word16_t  gamma2;          /**< Perceptual weighting coef 2 */
+
+   char  *stack;                  /**< Temporary allocation stack */
+   spx_word16_t *high;               /**< High-band signal (buffer) */
+   spx_word16_t *h0_mem, *h1_mem;
+
+   const spx_word16_t *window;    /**< LPC analysis window */
+   spx_word16_t *lagWindow;       /**< Auto-correlation window */
+   spx_lsp_t *old_lsp;            /**< LSPs of previous frame */
+   spx_lsp_t *old_qlsp;           /**< Quantized LSPs of previous frame */
+   spx_coef_t *interp_qlpc;       /**< Interpolated quantized LPCs for current sub-frame */
+
+   spx_mem_t *mem_sp;             /**< Synthesis signal memory */
+   spx_mem_t *mem_sp2;
+   spx_mem_t *mem_sw;             /**< Perceptual signal memory */
+   spx_word32_t *pi_gain;
+   spx_word16_t *exc_rms;
+   spx_word16_t *innov_rms_save;         /**< If non-NULL, innovation is copied here */
+
+   float  vbr_quality;            /**< Quality setting for VBR encoding */
+   int    vbr_enabled;            /**< 1 for enabling VBR, 0 otherwise */
+   spx_int32_t vbr_max;           /**< Max bit-rate allowed in VBR mode (total) */
+   spx_int32_t vbr_max_high;      /**< Max bit-rate allowed in VBR mode for the high-band */
+   spx_int32_t abr_enabled;       /**< ABR setting (in bps), 0 if off */
+   float  abr_drift;
+   float  abr_drift2;
+   float  abr_count;
+   int    vad_enabled;            /**< 1 for enabling VAD, 0 otherwise */
+   float  relative_quality;
+
+   int    encode_submode;
+   const SpeexSubmode * const *submodes;
+   int    submodeID;
+   int    submodeSelect;
+   int    complexity;
+   spx_int32_t sampling_rate;
+
+} SBEncState;
+
+
+/**Structure representing the full state of the sub-band decoder*/
+typedef struct SBDecState {
+   const SpeexMode *mode;            /**< Pointer to the mode (containing for vtable info) */
+   void *st_low;               /**< State of the low-band (narrowband) encoder */
+   int    full_frame_size;
+   int    frame_size;
+   int    subframeSize;
+   int    nbSubframes;
+   int    lpcSize;
+   int    first;
+   spx_int32_t sampling_rate;
+   int    lpc_enh_enabled;
+
+   char  *stack;
+   spx_word32_t *g0_mem, *g1_mem;
+
+   spx_word16_t *excBuf;
+   spx_lsp_t *old_qlsp;
+   spx_coef_t *interp_qlpc;
+
+   spx_mem_t *mem_sp;
+   spx_word32_t *pi_gain;
+   spx_word16_t *exc_rms;
+   spx_word16_t *innov_save;      /** If non-NULL, innovation is copied here */
+   
+   spx_word16_t last_ener;
+   spx_int32_t seed;
+
+   int    encode_submode;
+   const SpeexSubmode * const *submodes;
+   int    submodeID;
+} SBDecState;
+
+
+/**Initializes encoder state*/
+void *sb_encoder_init(const SpeexMode *m);
+
+/**De-allocates encoder state resources*/
+void sb_encoder_destroy(void *state);
+
+/**Encodes one frame*/
+int sb_encode(void *state, void *in, SpeexBits *bits);
+
+
+/**Initializes decoder state*/
+void *sb_decoder_init(const SpeexMode *m);
+
+/**De-allocates decoder state resources*/
+void sb_decoder_destroy(void *state);
+
+/**Decodes one frame*/
+int sb_decode(void *state, SpeexBits *bits, void *out);
+
+int sb_encoder_ctl(void *state, int request, void *ptr);
+
+int sb_decoder_ctl(void *state, int request, void *ptr);
+
+#endif
diff --git a/3rdparty/speex/libspeex/smallft.c b/3rdparty/speex/libspeex/smallft.c
new file mode 100644
index 0000000..269549d
--- /dev/null
+++ b/3rdparty/speex/libspeex/smallft.c
@@ -0,0 +1,1260 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001             *
+ * by the XIPHOPHORUS Company http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: *unnormalized* fft transform
+ last mod: $Id: smallft.c,v 1.19 2003/10/08 05:12:37 jm Exp $
+
+ ********************************************************************/
+
+/* FFT implementation from OggSquish, minus cosine transforms,
+ * minus all but radix 2/4 case.  In Vorbis we only need this
+ * cut-down version.
+ *
+ * To do more than just power-of-two sized vectors, see the full
+ * version I wrote for NetLib.
+ *
+ * Note that the packing is a little strange; rather than the FFT r/i
+ * packing following R_0, I_n, R_1, I_1, R_2, I_2 ... R_n-1, I_n-1,
+ * it follows R_0, R_1, I_1, R_2, I_2 ... R_n-1, I_n-1, I_n like the
+ * FORTRAN version
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include "smallft.h"
+#include "misc.h"
+
+static void drfti1(int n, float *wa, int *ifac){
+  static int ntryh[4] = { 4,2,3,5 };
+  static float tpi = 6.28318530717958648f;
+  float arg,argh,argld,fi;
+  int ntry=0,i,j=-1;
+  int k1, l1, l2, ib;
+  int ld, ii, ip, is, nq, nr;
+  int ido, ipm, nfm1;
+  int nl=n;
+  int nf=0;
+
+ L101:
+  j++;
+  if (j < 4)
+    ntry=ntryh[j];
+  else
+    ntry+=2;
+
+ L104:
+  nq=nl/ntry;
+  nr=nl-ntry*nq;
+  if (nr!=0) goto L101;
+
+  nf++;
+  ifac[nf+1]=ntry;
+  nl=nq;
+  if(ntry!=2)goto L107;
+  if(nf==1)goto L107;
+
+  for (i=1;i<nf;i++){
+    ib=nf-i+1;
+    ifac[ib+1]=ifac[ib];
+  }
+  ifac[2] = 2;
+
+ L107:
+  if(nl!=1)goto L104;
+  ifac[0]=n;
+  ifac[1]=nf;
+  argh=tpi/n;
+  is=0;
+  nfm1=nf-1;
+  l1=1;
+
+  if(nfm1==0)return;
+
+  for (k1=0;k1<nfm1;k1++){
+    ip=ifac[k1+2];
+    ld=0;
+    l2=l1*ip;
+    ido=n/l2;
+    ipm=ip-1;
+
+    for (j=0;j<ipm;j++){
+      ld+=l1;
+      i=is;
+      argld=(float)ld*argh;
+      fi=0.f;
+      for (ii=2;ii<ido;ii+=2){
+	fi+=1.f;
+	arg=fi*argld;
+	wa[i++]=cos(arg);
+	wa[i++]=sin(arg);
+      }
+      is+=ido;
+    }
+    l1=l2;
+  }
+}
+
+static void fdrffti(int n, float *wsave, int *ifac){
+
+  if (n == 1) return;
+  drfti1(n, wsave+n, ifac);
+}
+
+static void dradf2(int ido,int l1,float *cc,float *ch,float *wa1){
+  int i,k;
+  float ti2,tr2;
+  int t0,t1,t2,t3,t4,t5,t6;
+
+  t1=0;
+  t0=(t2=l1*ido);
+  t3=ido<<1;
+  for(k=0;k<l1;k++){
+    ch[t1<<1]=cc[t1]+cc[t2];
+    ch[(t1<<1)+t3-1]=cc[t1]-cc[t2];
+    t1+=ido;
+    t2+=ido;
+  }
+    
+  if(ido<2)return;
+  if(ido==2)goto L105;
+
+  t1=0;
+  t2=t0;
+  for(k=0;k<l1;k++){
+    t3=t2;
+    t4=(t1<<1)+(ido<<1);
+    t5=t1;
+    t6=t1+t1;
+    for(i=2;i<ido;i+=2){
+      t3+=2;
+      t4-=2;
+      t5+=2;
+      t6+=2;
+      tr2=wa1[i-2]*cc[t3-1]+wa1[i-1]*cc[t3];
+      ti2=wa1[i-2]*cc[t3]-wa1[i-1]*cc[t3-1];
+      ch[t6]=cc[t5]+ti2;
+      ch[t4]=ti2-cc[t5];
+      ch[t6-1]=cc[t5-1]+tr2;
+      ch[t4-1]=cc[t5-1]-tr2;
+    }
+    t1+=ido;
+    t2+=ido;
+  }
+
+  if(ido%2==1)return;
+
+ L105:
+  t3=(t2=(t1=ido)-1);
+  t2+=t0;
+  for(k=0;k<l1;k++){
+    ch[t1]=-cc[t2];
+    ch[t1-1]=cc[t3];
+    t1+=ido<<1;
+    t2+=ido;
+    t3+=ido;
+  }
+}
+
+static void dradf4(int ido,int l1,float *cc,float *ch,float *wa1,
+	    float *wa2,float *wa3){
+  static float hsqt2 = .70710678118654752f;
+  int i,k,t0,t1,t2,t3,t4,t5,t6;
+  float ci2,ci3,ci4,cr2,cr3,cr4,ti1,ti2,ti3,ti4,tr1,tr2,tr3,tr4;
+  t0=l1*ido;
+  
+  t1=t0;
+  t4=t1<<1;
+  t2=t1+(t1<<1);
+  t3=0;
+
+  for(k=0;k<l1;k++){
+    tr1=cc[t1]+cc[t2];
+    tr2=cc[t3]+cc[t4];
+
+    ch[t5=t3<<2]=tr1+tr2;
+    ch[(ido<<2)+t5-1]=tr2-tr1;
+    ch[(t5+=(ido<<1))-1]=cc[t3]-cc[t4];
+    ch[t5]=cc[t2]-cc[t1];
+
+    t1+=ido;
+    t2+=ido;
+    t3+=ido;
+    t4+=ido;
+  }
+
+  if(ido<2)return;
+  if(ido==2)goto L105;
+
+
+  t1=0;
+  for(k=0;k<l1;k++){
+    t2=t1;
+    t4=t1<<2;
+    t5=(t6=ido<<1)+t4;
+    for(i=2;i<ido;i+=2){
+      t3=(t2+=2);
+      t4+=2;
+      t5-=2;
+
+      t3+=t0;
+      cr2=wa1[i-2]*cc[t3-1]+wa1[i-1]*cc[t3];
+      ci2=wa1[i-2]*cc[t3]-wa1[i-1]*cc[t3-1];
+      t3+=t0;
+      cr3=wa2[i-2]*cc[t3-1]+wa2[i-1]*cc[t3];
+      ci3=wa2[i-2]*cc[t3]-wa2[i-1]*cc[t3-1];
+      t3+=t0;
+      cr4=wa3[i-2]*cc[t3-1]+wa3[i-1]*cc[t3];
+      ci4=wa3[i-2]*cc[t3]-wa3[i-1]*cc[t3-1];
+
+      tr1=cr2+cr4;
+      tr4=cr4-cr2;
+      ti1=ci2+ci4;
+      ti4=ci2-ci4;
+
+      ti2=cc[t2]+ci3;
+      ti3=cc[t2]-ci3;
+      tr2=cc[t2-1]+cr3;
+      tr3=cc[t2-1]-cr3;
+
+      ch[t4-1]=tr1+tr2;
+      ch[t4]=ti1+ti2;
+
+      ch[t5-1]=tr3-ti4;
+      ch[t5]=tr4-ti3;
+
+      ch[t4+t6-1]=ti4+tr3;
+      ch[t4+t6]=tr4+ti3;
+
+      ch[t5+t6-1]=tr2-tr1;
+      ch[t5+t6]=ti1-ti2;
+    }
+    t1+=ido;
+  }
+  if(ido&1)return;
+
+ L105:
+  
+  t2=(t1=t0+ido-1)+(t0<<1);
+  t3=ido<<2;
+  t4=ido;
+  t5=ido<<1;
+  t6=ido;
+
+  for(k=0;k<l1;k++){
+    ti1=-hsqt2*(cc[t1]+cc[t2]);
+    tr1=hsqt2*(cc[t1]-cc[t2]);
+
+    ch[t4-1]=tr1+cc[t6-1];
+    ch[t4+t5-1]=cc[t6-1]-tr1;
+
+    ch[t4]=ti1-cc[t1+t0];
+    ch[t4+t5]=ti1+cc[t1+t0];
+
+    t1+=ido;
+    t2+=ido;
+    t4+=t3;
+    t6+=ido;
+  }
+}
+
+static void dradfg(int ido,int ip,int l1,int idl1,float *cc,float *c1,
+                          float *c2,float *ch,float *ch2,float *wa){
+
+  static float tpi=6.283185307179586f;
+  int idij,ipph,i,j,k,l,ic,ik,is;
+  int t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10;
+  float dc2,ai1,ai2,ar1,ar2,ds2;
+  int nbd;
+  float dcp,arg,dsp,ar1h,ar2h;
+  int idp2,ipp2;
+  
+  arg=tpi/(float)ip;
+  dcp=cos(arg);
+  dsp=sin(arg);
+  ipph=(ip+1)>>1;
+  ipp2=ip;
+  idp2=ido;
+  nbd=(ido-1)>>1;
+  t0=l1*ido;
+  t10=ip*ido;
+
+  if(ido==1)goto L119;
+  for(ik=0;ik<idl1;ik++)ch2[ik]=c2[ik];
+
+  t1=0;
+  for(j=1;j<ip;j++){
+    t1+=t0;
+    t2=t1;
+    for(k=0;k<l1;k++){
+      ch[t2]=c1[t2];
+      t2+=ido;
+    }
+  }
+
+  is=-ido;
+  t1=0;
+  if(nbd>l1){
+    for(j=1;j<ip;j++){
+      t1+=t0;
+      is+=ido;
+      t2= -ido+t1;
+      for(k=0;k<l1;k++){
+        idij=is-1;
+        t2+=ido;
+        t3=t2;
+        for(i=2;i<ido;i+=2){
+          idij+=2;
+          t3+=2;
+          ch[t3-1]=wa[idij-1]*c1[t3-1]+wa[idij]*c1[t3];
+          ch[t3]=wa[idij-1]*c1[t3]-wa[idij]*c1[t3-1];
+        }
+      }
+    }
+  }else{
+
+    for(j=1;j<ip;j++){
+      is+=ido;
+      idij=is-1;
+      t1+=t0;
+      t2=t1;
+      for(i=2;i<ido;i+=2){
+        idij+=2;
+        t2+=2;
+        t3=t2;
+        for(k=0;k<l1;k++){
+          ch[t3-1]=wa[idij-1]*c1[t3-1]+wa[idij]*c1[t3];
+          ch[t3]=wa[idij-1]*c1[t3]-wa[idij]*c1[t3-1];
+          t3+=ido;
+        }
+      }
+    }
+  }
+
+  t1=0;
+  t2=ipp2*t0;
+  if(nbd<l1){
+    for(j=1;j<ipph;j++){
+      t1+=t0;
+      t2-=t0;
+      t3=t1;
+      t4=t2;
+      for(i=2;i<ido;i+=2){
+        t3+=2;
+        t4+=2;
+        t5=t3-ido;
+        t6=t4-ido;
+        for(k=0;k<l1;k++){
+          t5+=ido;
+          t6+=ido;
+          c1[t5-1]=ch[t5-1]+ch[t6-1];
+          c1[t6-1]=ch[t5]-ch[t6];
+          c1[t5]=ch[t5]+ch[t6];
+          c1[t6]=ch[t6-1]-ch[t5-1];
+        }
+      }
+    }
+  }else{
+    for(j=1;j<ipph;j++){
+      t1+=t0;
+      t2-=t0;
+      t3=t1;
+      t4=t2;
+      for(k=0;k<l1;k++){
+        t5=t3;
+        t6=t4;
+        for(i=2;i<ido;i+=2){
+          t5+=2;
+          t6+=2;
+          c1[t5-1]=ch[t5-1]+ch[t6-1];
+          c1[t6-1]=ch[t5]-ch[t6];
+          c1[t5]=ch[t5]+ch[t6];
+          c1[t6]=ch[t6-1]-ch[t5-1];
+        }
+        t3+=ido;
+        t4+=ido;
+      }
+    }
+  }
+
+L119:
+  for(ik=0;ik<idl1;ik++)c2[ik]=ch2[ik];
+
+  t1=0;
+  t2=ipp2*idl1;
+  for(j=1;j<ipph;j++){
+    t1+=t0;
+    t2-=t0;
+    t3=t1-ido;
+    t4=t2-ido;
+    for(k=0;k<l1;k++){
+      t3+=ido;
+      t4+=ido;
+      c1[t3]=ch[t3]+ch[t4];
+      c1[t4]=ch[t4]-ch[t3];
+    }
+  }
+
+  ar1=1.f;
+  ai1=0.f;
+  t1=0;
+  t2=ipp2*idl1;
+  t3=(ip-1)*idl1;
+  for(l=1;l<ipph;l++){
+    t1+=idl1;
+    t2-=idl1;
+    ar1h=dcp*ar1-dsp*ai1;
+    ai1=dcp*ai1+dsp*ar1;
+    ar1=ar1h;
+    t4=t1;
+    t5=t2;
+    t6=t3;
+    t7=idl1;
+
+    for(ik=0;ik<idl1;ik++){
+      ch2[t4++]=c2[ik]+ar1*c2[t7++];
+      ch2[t5++]=ai1*c2[t6++];
+    }
+
+    dc2=ar1;
+    ds2=ai1;
+    ar2=ar1;
+    ai2=ai1;
+
+    t4=idl1;
+    t5=(ipp2-1)*idl1;
+    for(j=2;j<ipph;j++){
+      t4+=idl1;
+      t5-=idl1;
+
+      ar2h=dc2*ar2-ds2*ai2;
+      ai2=dc2*ai2+ds2*ar2;
+      ar2=ar2h;
+
+      t6=t1;
+      t7=t2;
+      t8=t4;
+      t9=t5;
+      for(ik=0;ik<idl1;ik++){
+        ch2[t6++]+=ar2*c2[t8++];
+        ch2[t7++]+=ai2*c2[t9++];
+      }
+    }
+  }
+
+  t1=0;
+  for(j=1;j<ipph;j++){
+    t1+=idl1;
+    t2=t1;
+    for(ik=0;ik<idl1;ik++)ch2[ik]+=c2[t2++];
+  }
+
+  if(ido<l1)goto L132;
+
+  t1=0;
+  t2=0;
+  for(k=0;k<l1;k++){
+    t3=t1;
+    t4=t2;
+    for(i=0;i<ido;i++)cc[t4++]=ch[t3++];
+    t1+=ido;
+    t2+=t10;
+  }
+
+  goto L135;
+
+ L132:
+  for(i=0;i<ido;i++){
+    t1=i;
+    t2=i;
+    for(k=0;k<l1;k++){
+      cc[t2]=ch[t1];
+      t1+=ido;
+      t2+=t10;
+    }
+  }
+
+ L135:
+  t1=0;
+  t2=ido<<1;
+  t3=0;
+  t4=ipp2*t0;
+  for(j=1;j<ipph;j++){
+
+    t1+=t2;
+    t3+=t0;
+    t4-=t0;
+
+    t5=t1;
+    t6=t3;
+    t7=t4;
+
+    for(k=0;k<l1;k++){
+      cc[t5-1]=ch[t6];
+      cc[t5]=ch[t7];
+      t5+=t10;
+      t6+=ido;
+      t7+=ido;
+    }
+  }
+
+  if(ido==1)return;
+  if(nbd<l1)goto L141;
+
+  t1=-ido;
+  t3=0;
+  t4=0;
+  t5=ipp2*t0;
+  for(j=1;j<ipph;j++){
+    t1+=t2;
+    t3+=t2;
+    t4+=t0;
+    t5-=t0;
+    t6=t1;
+    t7=t3;
+    t8=t4;
+    t9=t5;
+    for(k=0;k<l1;k++){
+      for(i=2;i<ido;i+=2){
+        ic=idp2-i;
+        cc[i+t7-1]=ch[i+t8-1]+ch[i+t9-1];
+        cc[ic+t6-1]=ch[i+t8-1]-ch[i+t9-1];
+        cc[i+t7]=ch[i+t8]+ch[i+t9];
+        cc[ic+t6]=ch[i+t9]-ch[i+t8];
+      }
+      t6+=t10;
+      t7+=t10;
+      t8+=ido;
+      t9+=ido;
+    }
+  }
+  return;
+
+ L141:
+
+  t1=-ido;
+  t3=0;
+  t4=0;
+  t5=ipp2*t0;
+  for(j=1;j<ipph;j++){
+    t1+=t2;
+    t3+=t2;
+    t4+=t0;
+    t5-=t0;
+    for(i=2;i<ido;i+=2){
+      t6=idp2+t1-i;
+      t7=i+t3;
+      t8=i+t4;
+      t9=i+t5;
+      for(k=0;k<l1;k++){
+        cc[t7-1]=ch[t8-1]+ch[t9-1];
+        cc[t6-1]=ch[t8-1]-ch[t9-1];
+        cc[t7]=ch[t8]+ch[t9];
+        cc[t6]=ch[t9]-ch[t8];
+        t6+=t10;
+        t7+=t10;
+        t8+=ido;
+        t9+=ido;
+      }
+    }
+  }
+}
+
+static void drftf1(int n,float *c,float *ch,float *wa,int *ifac){
+  int i,k1,l1,l2;
+  int na,kh,nf;
+  int ip,iw,ido,idl1,ix2,ix3;
+
+  nf=ifac[1];
+  na=1;
+  l2=n;
+  iw=n;
+
+  for(k1=0;k1<nf;k1++){
+    kh=nf-k1;
+    ip=ifac[kh+1];
+    l1=l2/ip;
+    ido=n/l2;
+    idl1=ido*l1;
+    iw-=(ip-1)*ido;
+    na=1-na;
+
+    if(ip!=4)goto L102;
+
+    ix2=iw+ido;
+    ix3=ix2+ido;
+    if(na!=0)
+      dradf4(ido,l1,ch,c,wa+iw-1,wa+ix2-1,wa+ix3-1);
+    else
+      dradf4(ido,l1,c,ch,wa+iw-1,wa+ix2-1,wa+ix3-1);
+    goto L110;
+
+ L102:
+    if(ip!=2)goto L104;
+    if(na!=0)goto L103;
+
+    dradf2(ido,l1,c,ch,wa+iw-1);
+    goto L110;
+
+  L103:
+    dradf2(ido,l1,ch,c,wa+iw-1);
+    goto L110;
+
+  L104:
+    if(ido==1)na=1-na;
+    if(na!=0)goto L109;
+
+    dradfg(ido,ip,l1,idl1,c,c,c,ch,ch,wa+iw-1);
+    na=1;
+    goto L110;
+
+  L109:
+    dradfg(ido,ip,l1,idl1,ch,ch,ch,c,c,wa+iw-1);
+    na=0;
+
+  L110:
+    l2=l1;
+  }
+
+  if(na==1)return;
+
+  for(i=0;i<n;i++)c[i]=ch[i];
+}
+
+static void dradb2(int ido,int l1,float *cc,float *ch,float *wa1){
+  int i,k,t0,t1,t2,t3,t4,t5,t6;
+  float ti2,tr2;
+
+  t0=l1*ido;
+  
+  t1=0;
+  t2=0;
+  t3=(ido<<1)-1;
+  for(k=0;k<l1;k++){
+    ch[t1]=cc[t2]+cc[t3+t2];
+    ch[t1+t0]=cc[t2]-cc[t3+t2];
+    t2=(t1+=ido)<<1;
+  }
+
+  if(ido<2)return;
+  if(ido==2)goto L105;
+
+  t1=0;
+  t2=0;
+  for(k=0;k<l1;k++){
+    t3=t1;
+    t5=(t4=t2)+(ido<<1);
+    t6=t0+t1;
+    for(i=2;i<ido;i+=2){
+      t3+=2;
+      t4+=2;
+      t5-=2;
+      t6+=2;
+      ch[t3-1]=cc[t4-1]+cc[t5-1];
+      tr2=cc[t4-1]-cc[t5-1];
+      ch[t3]=cc[t4]-cc[t5];
+      ti2=cc[t4]+cc[t5];
+      ch[t6-1]=wa1[i-2]*tr2-wa1[i-1]*ti2;
+      ch[t6]=wa1[i-2]*ti2+wa1[i-1]*tr2;
+    }
+    t2=(t1+=ido)<<1;
+  }
+
+  if(ido%2==1)return;
+
+L105:
+  t1=ido-1;
+  t2=ido-1;
+  for(k=0;k<l1;k++){
+    ch[t1]=cc[t2]+cc[t2];
+    ch[t1+t0]=-(cc[t2+1]+cc[t2+1]);
+    t1+=ido;
+    t2+=ido<<1;
+  }
+}
+
+static void dradb3(int ido,int l1,float *cc,float *ch,float *wa1,
+                          float *wa2){
+  static float taur = -.5f;
+  static float taui = .8660254037844386f;
+  int i,k,t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10;
+  float ci2,ci3,di2,di3,cr2,cr3,dr2,dr3,ti2,tr2;
+  t0=l1*ido;
+
+  t1=0;
+  t2=t0<<1;
+  t3=ido<<1;
+  t4=ido+(ido<<1);
+  t5=0;
+  for(k=0;k<l1;k++){
+    tr2=cc[t3-1]+cc[t3-1];
+    cr2=cc[t5]+(taur*tr2);
+    ch[t1]=cc[t5]+tr2;
+    ci3=taui*(cc[t3]+cc[t3]);
+    ch[t1+t0]=cr2-ci3;
+    ch[t1+t2]=cr2+ci3;
+    t1+=ido;
+    t3+=t4;
+    t5+=t4;
+  }
+
+  if(ido==1)return;
+
+  t1=0;
+  t3=ido<<1;
+  for(k=0;k<l1;k++){
+    t7=t1+(t1<<1);
+    t6=(t5=t7+t3);
+    t8=t1;
+    t10=(t9=t1+t0)+t0;
+
+    for(i=2;i<ido;i+=2){
+      t5+=2;
+      t6-=2;
+      t7+=2;
+      t8+=2;
+      t9+=2;
+      t10+=2;
+      tr2=cc[t5-1]+cc[t6-1];
+      cr2=cc[t7-1]+(taur*tr2);
+      ch[t8-1]=cc[t7-1]+tr2;
+      ti2=cc[t5]-cc[t6];
+      ci2=cc[t7]+(taur*ti2);
+      ch[t8]=cc[t7]+ti2;
+      cr3=taui*(cc[t5-1]-cc[t6-1]);
+      ci3=taui*(cc[t5]+cc[t6]);
+      dr2=cr2-ci3;
+      dr3=cr2+ci3;
+      di2=ci2+cr3;
+      di3=ci2-cr3;
+      ch[t9-1]=wa1[i-2]*dr2-wa1[i-1]*di2;
+      ch[t9]=wa1[i-2]*di2+wa1[i-1]*dr2;
+      ch[t10-1]=wa2[i-2]*dr3-wa2[i-1]*di3;
+      ch[t10]=wa2[i-2]*di3+wa2[i-1]*dr3;
+    }
+    t1+=ido;
+  }
+}
+
+static void dradb4(int ido,int l1,float *cc,float *ch,float *wa1,
+			  float *wa2,float *wa3){
+  static float sqrt2=1.414213562373095f;
+  int i,k,t0,t1,t2,t3,t4,t5,t6,t7,t8;
+  float ci2,ci3,ci4,cr2,cr3,cr4,ti1,ti2,ti3,ti4,tr1,tr2,tr3,tr4;
+  t0=l1*ido;
+  
+  t1=0;
+  t2=ido<<2;
+  t3=0;
+  t6=ido<<1;
+  for(k=0;k<l1;k++){
+    t4=t3+t6;
+    t5=t1;
+    tr3=cc[t4-1]+cc[t4-1];
+    tr4=cc[t4]+cc[t4]; 
+    tr1=cc[t3]-cc[(t4+=t6)-1];
+    tr2=cc[t3]+cc[t4-1];
+    ch[t5]=tr2+tr3;
+    ch[t5+=t0]=tr1-tr4;
+    ch[t5+=t0]=tr2-tr3;
+    ch[t5+=t0]=tr1+tr4;
+    t1+=ido;
+    t3+=t2;
+  }
+
+  if(ido<2)return;
+  if(ido==2)goto L105;
+
+  t1=0;
+  for(k=0;k<l1;k++){
+    t5=(t4=(t3=(t2=t1<<2)+t6))+t6;
+    t7=t1;
+    for(i=2;i<ido;i+=2){
+      t2+=2;
+      t3+=2;
+      t4-=2;
+      t5-=2;
+      t7+=2;
+      ti1=cc[t2]+cc[t5];
+      ti2=cc[t2]-cc[t5];
+      ti3=cc[t3]-cc[t4];
+      tr4=cc[t3]+cc[t4];
+      tr1=cc[t2-1]-cc[t5-1];
+      tr2=cc[t2-1]+cc[t5-1];
+      ti4=cc[t3-1]-cc[t4-1];
+      tr3=cc[t3-1]+cc[t4-1];
+      ch[t7-1]=tr2+tr3;
+      cr3=tr2-tr3;
+      ch[t7]=ti2+ti3;
+      ci3=ti2-ti3;
+      cr2=tr1-tr4;
+      cr4=tr1+tr4;
+      ci2=ti1+ti4;
+      ci4=ti1-ti4;
+
+      ch[(t8=t7+t0)-1]=wa1[i-2]*cr2-wa1[i-1]*ci2;
+      ch[t8]=wa1[i-2]*ci2+wa1[i-1]*cr2;
+      ch[(t8+=t0)-1]=wa2[i-2]*cr3-wa2[i-1]*ci3;
+      ch[t8]=wa2[i-2]*ci3+wa2[i-1]*cr3;
+      ch[(t8+=t0)-1]=wa3[i-2]*cr4-wa3[i-1]*ci4;
+      ch[t8]=wa3[i-2]*ci4+wa3[i-1]*cr4;
+    }
+    t1+=ido;
+  }
+
+  if(ido%2 == 1)return;
+
+ L105:
+
+  t1=ido;
+  t2=ido<<2;
+  t3=ido-1;
+  t4=ido+(ido<<1);
+  for(k=0;k<l1;k++){
+    t5=t3;
+    ti1=cc[t1]+cc[t4];
+    ti2=cc[t4]-cc[t1];
+    tr1=cc[t1-1]-cc[t4-1];
+    tr2=cc[t1-1]+cc[t4-1];
+    ch[t5]=tr2+tr2;
+    ch[t5+=t0]=sqrt2*(tr1-ti1);
+    ch[t5+=t0]=ti2+ti2;
+    ch[t5+=t0]=-sqrt2*(tr1+ti1);
+
+    t3+=ido;
+    t1+=t2;
+    t4+=t2;
+  }
+}
+
+static void dradbg(int ido,int ip,int l1,int idl1,float *cc,float *c1,
+            float *c2,float *ch,float *ch2,float *wa){
+  static float tpi=6.283185307179586f;
+  int idij,ipph,i,j,k,l,ik,is,t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,
+      t11,t12;
+  float dc2,ai1,ai2,ar1,ar2,ds2;
+  int nbd;
+  float dcp,arg,dsp,ar1h,ar2h;
+  int ipp2;
+
+  t10=ip*ido;
+  t0=l1*ido;
+  arg=tpi/(float)ip;
+  dcp=cos(arg);
+  dsp=sin(arg);
+  nbd=(ido-1)>>1;
+  ipp2=ip;
+  ipph=(ip+1)>>1;
+  if(ido<l1)goto L103;
+  
+  t1=0;
+  t2=0;
+  for(k=0;k<l1;k++){
+    t3=t1;
+    t4=t2;
+    for(i=0;i<ido;i++){
+      ch[t3]=cc[t4];
+      t3++;
+      t4++;
+    }
+    t1+=ido;
+    t2+=t10;
+  }
+  goto L106;
+
+ L103:
+  t1=0;
+  for(i=0;i<ido;i++){
+    t2=t1;
+    t3=t1;
+    for(k=0;k<l1;k++){
+      ch[t2]=cc[t3];
+      t2+=ido;
+      t3+=t10;
+    }
+    t1++;
+  }
+
+ L106:
+  t1=0;
+  t2=ipp2*t0;
+  t7=(t5=ido<<1);
+  for(j=1;j<ipph;j++){
+    t1+=t0;
+    t2-=t0;
+    t3=t1;
+    t4=t2;
+    t6=t5;
+    for(k=0;k<l1;k++){
+      ch[t3]=cc[t6-1]+cc[t6-1];
+      ch[t4]=cc[t6]+cc[t6];
+      t3+=ido;
+      t4+=ido;
+      t6+=t10;
+    }
+    t5+=t7;
+  }
+
+  if (ido == 1)goto L116;
+  if(nbd<l1)goto L112;
+
+  t1=0;
+  t2=ipp2*t0;
+  t7=0;
+  for(j=1;j<ipph;j++){
+    t1+=t0;
+    t2-=t0;
+    t3=t1;
+    t4=t2;
+
+    t7+=(ido<<1);
+    t8=t7;
+    for(k=0;k<l1;k++){
+      t5=t3;
+      t6=t4;
+      t9=t8;
+      t11=t8;
+      for(i=2;i<ido;i+=2){
+        t5+=2;
+        t6+=2;
+        t9+=2;
+        t11-=2;
+        ch[t5-1]=cc[t9-1]+cc[t11-1];
+        ch[t6-1]=cc[t9-1]-cc[t11-1];
+        ch[t5]=cc[t9]-cc[t11];
+        ch[t6]=cc[t9]+cc[t11];
+      }
+      t3+=ido;
+      t4+=ido;
+      t8+=t10;
+    }
+  }
+  goto L116;
+
+ L112:
+  t1=0;
+  t2=ipp2*t0;
+  t7=0;
+  for(j=1;j<ipph;j++){
+    t1+=t0;
+    t2-=t0;
+    t3=t1;
+    t4=t2;
+    t7+=(ido<<1);
+    t8=t7;
+    t9=t7;
+    for(i=2;i<ido;i+=2){
+      t3+=2;
+      t4+=2;
+      t8+=2;
+      t9-=2;
+      t5=t3;
+      t6=t4;
+      t11=t8;
+      t12=t9;
+      for(k=0;k<l1;k++){
+        ch[t5-1]=cc[t11-1]+cc[t12-1];
+        ch[t6-1]=cc[t11-1]-cc[t12-1];
+        ch[t5]=cc[t11]-cc[t12];
+        ch[t6]=cc[t11]+cc[t12];
+        t5+=ido;
+        t6+=ido;
+        t11+=t10;
+        t12+=t10;
+      }
+    }
+  }
+
+L116:
+  ar1=1.f;
+  ai1=0.f;
+  t1=0;
+  t9=(t2=ipp2*idl1);
+  t3=(ip-1)*idl1;
+  for(l=1;l<ipph;l++){
+    t1+=idl1;
+    t2-=idl1;
+
+    ar1h=dcp*ar1-dsp*ai1;
+    ai1=dcp*ai1+dsp*ar1;
+    ar1=ar1h;
+    t4=t1;
+    t5=t2;
+    t6=0;
+    t7=idl1;
+    t8=t3;
+    for(ik=0;ik<idl1;ik++){
+      c2[t4++]=ch2[t6++]+ar1*ch2[t7++];
+      c2[t5++]=ai1*ch2[t8++];
+    }
+    dc2=ar1;
+    ds2=ai1;
+    ar2=ar1;
+    ai2=ai1;
+
+    t6=idl1;
+    t7=t9-idl1;
+    for(j=2;j<ipph;j++){
+      t6+=idl1;
+      t7-=idl1;
+      ar2h=dc2*ar2-ds2*ai2;
+      ai2=dc2*ai2+ds2*ar2;
+      ar2=ar2h;
+      t4=t1;
+      t5=t2;
+      t11=t6;
+      t12=t7;
+      for(ik=0;ik<idl1;ik++){
+        c2[t4++]+=ar2*ch2[t11++];
+        c2[t5++]+=ai2*ch2[t12++];
+      }
+    }
+  }
+
+  t1=0;
+  for(j=1;j<ipph;j++){
+    t1+=idl1;
+    t2=t1;
+    for(ik=0;ik<idl1;ik++)ch2[ik]+=ch2[t2++];
+  }
+
+  t1=0;
+  t2=ipp2*t0;
+  for(j=1;j<ipph;j++){
+    t1+=t0;
+    t2-=t0;
+    t3=t1;
+    t4=t2;
+    for(k=0;k<l1;k++){
+      ch[t3]=c1[t3]-c1[t4];
+      ch[t4]=c1[t3]+c1[t4];
+      t3+=ido;
+      t4+=ido;
+    }
+  }
+
+  if(ido==1)goto L132;
+  if(nbd<l1)goto L128;
+
+  t1=0;
+  t2=ipp2*t0;
+  for(j=1;j<ipph;j++){
+    t1+=t0;
+    t2-=t0;
+    t3=t1;
+    t4=t2;
+    for(k=0;k<l1;k++){
+      t5=t3;
+      t6=t4;
+      for(i=2;i<ido;i+=2){
+        t5+=2;
+        t6+=2;
+        ch[t5-1]=c1[t5-1]-c1[t6];
+        ch[t6-1]=c1[t5-1]+c1[t6];
+        ch[t5]=c1[t5]+c1[t6-1];
+        ch[t6]=c1[t5]-c1[t6-1];
+      }
+      t3+=ido;
+      t4+=ido;
+    }
+  }
+  goto L132;
+
+ L128:
+  t1=0;
+  t2=ipp2*t0;
+  for(j=1;j<ipph;j++){
+    t1+=t0;
+    t2-=t0;
+    t3=t1;
+    t4=t2;
+    for(i=2;i<ido;i+=2){
+      t3+=2;
+      t4+=2;
+      t5=t3;
+      t6=t4;
+      for(k=0;k<l1;k++){
+        ch[t5-1]=c1[t5-1]-c1[t6];
+        ch[t6-1]=c1[t5-1]+c1[t6];
+        ch[t5]=c1[t5]+c1[t6-1];
+        ch[t6]=c1[t5]-c1[t6-1];
+        t5+=ido;
+        t6+=ido;
+      }
+    }
+  }
+
+L132:
+  if(ido==1)return;
+
+  for(ik=0;ik<idl1;ik++)c2[ik]=ch2[ik];
+
+  t1=0;
+  for(j=1;j<ip;j++){
+    t2=(t1+=t0);
+    for(k=0;k<l1;k++){
+      c1[t2]=ch[t2];
+      t2+=ido;
+    }
+  }
+
+  if(nbd>l1)goto L139;
+
+  is= -ido-1;
+  t1=0;
+  for(j=1;j<ip;j++){
+    is+=ido;
+    t1+=t0;
+    idij=is;
+    t2=t1;
+    for(i=2;i<ido;i+=2){
+      t2+=2;
+      idij+=2;
+      t3=t2;
+      for(k=0;k<l1;k++){
+        c1[t3-1]=wa[idij-1]*ch[t3-1]-wa[idij]*ch[t3];
+        c1[t3]=wa[idij-1]*ch[t3]+wa[idij]*ch[t3-1];
+        t3+=ido;
+      }
+    }
+  }
+  return;
+
+ L139:
+  is= -ido-1;
+  t1=0;
+  for(j=1;j<ip;j++){
+    is+=ido;
+    t1+=t0;
+    t2=t1;
+    for(k=0;k<l1;k++){
+      idij=is;
+      t3=t2;
+      for(i=2;i<ido;i+=2){
+        idij+=2;
+        t3+=2;
+        c1[t3-1]=wa[idij-1]*ch[t3-1]-wa[idij]*ch[t3];
+        c1[t3]=wa[idij-1]*ch[t3]+wa[idij]*ch[t3-1];
+      }
+      t2+=ido;
+    }
+  }
+}
+
+static void drftb1(int n, float *c, float *ch, float *wa, int *ifac){
+  int i,k1,l1,l2;
+  int na;
+  int nf,ip,iw,ix2,ix3,ido,idl1;
+
+  nf=ifac[1];
+  na=0;
+  l1=1;
+  iw=1;
+
+  for(k1=0;k1<nf;k1++){
+    ip=ifac[k1 + 2];
+    l2=ip*l1;
+    ido=n/l2;
+    idl1=ido*l1;
+    if(ip!=4)goto L103;
+    ix2=iw+ido;
+    ix3=ix2+ido;
+
+    if(na!=0)
+      dradb4(ido,l1,ch,c,wa+iw-1,wa+ix2-1,wa+ix3-1);
+    else
+      dradb4(ido,l1,c,ch,wa+iw-1,wa+ix2-1,wa+ix3-1);
+    na=1-na;
+    goto L115;
+
+  L103:
+    if(ip!=2)goto L106;
+
+    if(na!=0)
+      dradb2(ido,l1,ch,c,wa+iw-1);
+    else
+      dradb2(ido,l1,c,ch,wa+iw-1);
+    na=1-na;
+    goto L115;
+
+  L106:
+    if(ip!=3)goto L109;
+
+    ix2=iw+ido;
+    if(na!=0)
+      dradb3(ido,l1,ch,c,wa+iw-1,wa+ix2-1);
+    else
+      dradb3(ido,l1,c,ch,wa+iw-1,wa+ix2-1);
+    na=1-na;
+    goto L115;
+
+  L109:
+/*    The radix five case can be translated later..... */
+/*    if(ip!=5)goto L112;
+
+    ix2=iw+ido;
+    ix3=ix2+ido;
+    ix4=ix3+ido;
+    if(na!=0)
+      dradb5(ido,l1,ch,c,wa+iw-1,wa+ix2-1,wa+ix3-1,wa+ix4-1);
+    else
+      dradb5(ido,l1,c,ch,wa+iw-1,wa+ix2-1,wa+ix3-1,wa+ix4-1);
+    na=1-na;
+    goto L115;
+
+  L112:*/
+    if(na!=0)
+      dradbg(ido,ip,l1,idl1,ch,ch,ch,c,c,wa+iw-1);
+    else
+      dradbg(ido,ip,l1,idl1,c,c,c,ch,ch,wa+iw-1);
+    if(ido==1)na=1-na;
+
+  L115:
+    l1=l2;
+    iw+=(ip-1)*ido;
+  }
+
+  if(na==0)return;
+
+  for(i=0;i<n;i++)c[i]=ch[i];
+}
+
+void spx_drft_forward(struct drft_lookup *l,float *data){
+  if(l->n==1)return;
+  drftf1(l->n,data,l->trigcache,l->trigcache+l->n,l->splitcache);
+}
+
+void spx_drft_backward(struct drft_lookup *l,float *data){
+  if (l->n==1)return;
+  drftb1(l->n,data,l->trigcache,l->trigcache+l->n,l->splitcache);
+}
+
+void spx_drft_init(struct drft_lookup *l,int n)
+{
+  l->n=n;
+  l->trigcache=(float*)speex_alloc(3*n*sizeof(*l->trigcache));
+  l->splitcache=(int*)speex_alloc(32*sizeof(*l->splitcache));
+  fdrffti(n, l->trigcache, l->splitcache);
+}
+
+void spx_drft_clear(struct drft_lookup *l)
+{
+  if(l)
+  {
+    if(l->trigcache)
+      speex_free(l->trigcache);
+    if(l->splitcache)
+      speex_free(l->splitcache);
+  }
+}
diff --git a/3rdparty/speex/libspeex/smallft.h b/3rdparty/speex/libspeex/smallft.h
new file mode 100644
index 0000000..446e2f6
--- /dev/null
+++ b/3rdparty/speex/libspeex/smallft.h
@@ -0,0 +1,46 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001             *
+ * by the XIPHOPHORUS Company http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: fft transform
+ last mod: $Id: smallft.h,v 1.3 2003/09/16 18:35:45 jm Exp $
+
+ ********************************************************************/
+/**
+   @file smallft.h
+   @brief Discrete Rotational Fourier Transform (DRFT)
+*/
+
+#ifndef _V_SMFT_H_
+#define _V_SMFT_H_
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Discrete Rotational Fourier Transform lookup */
+struct drft_lookup{
+  int n;
+  float *trigcache;
+  int *splitcache;
+};
+
+extern void spx_drft_forward(struct drft_lookup *l,float *data);
+extern void spx_drft_backward(struct drft_lookup *l,float *data);
+extern void spx_drft_init(struct drft_lookup *l,int n);
+extern void spx_drft_clear(struct drft_lookup *l);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/3rdparty/speex/libspeex/speex.c b/3rdparty/speex/libspeex/speex.c
new file mode 100644
index 0000000..846e021
--- /dev/null
+++ b/3rdparty/speex/libspeex/speex.c
@@ -0,0 +1,268 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: speex.c
+
+   Basic Speex functions
+
+   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 <math.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define MAX_IN_SAMPLES 640
+
+
+
+void *speex_encoder_init(const SpeexMode *mode)
+{
+   return mode->enc_init(mode);
+}
+
+void *speex_decoder_init(const SpeexMode *mode)
+{
+   return mode->dec_init(mode);
+}
+
+void speex_encoder_destroy(void *state)
+{
+   (*((SpeexMode**)state))->enc_destroy(state);
+}
+
+void speex_decoder_destroy(void *state)
+{
+   (*((SpeexMode**)state))->dec_destroy(state);
+}
+
+
+
+int speex_encode_native(void *state, spx_word16_t *in, SpeexBits *bits)
+{
+   return (*((SpeexMode**)state))->enc(state, in, bits);
+}
+
+int speex_decode_native(void *state, SpeexBits *bits, spx_word16_t *out)
+{
+   return (*((SpeexMode**)state))->dec(state, bits, out);
+}
+
+
+
+#ifdef FIXED_POINT
+
+int speex_encode(void *state, float *in, SpeexBits *bits)
+{
+   int i;
+   spx_int32_t N;
+   spx_int16_t short_in[MAX_IN_SAMPLES];
+   speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N);
+   for (i=0;i<N;i++)
+   {
+      if (in[i]>32767.f)
+         short_in[i] = 32767;
+      else if (in[i]<-32768.f)
+         short_in[i] = -32768;
+      else
+         short_in[i] = (spx_int16_t)floor(.5+in[i]);
+   }
+   return (*((SpeexMode**)state))->enc(state, short_in, bits);
+}
+
+int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
+{
+   SpeexMode *mode;
+   mode = *(SpeexMode**)state;
+   return (mode)->enc(state, in, bits);
+}
+
+int speex_decode(void *state, SpeexBits *bits, float *out)
+{
+   int i, ret;
+   spx_int32_t N;
+   spx_int16_t short_out[MAX_IN_SAMPLES];
+   speex_decoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N);
+   ret = (*((SpeexMode**)state))->dec(state, bits, short_out);
+   for (i=0;i<N;i++)
+      out[i] = short_out[i];
+   return ret;
+}
+
+int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
+{
+   SpeexMode *mode = *(SpeexMode**)state;
+   return (mode)->dec(state, bits, out);
+}
+
+#else
+
+int speex_encode(void *state, float *in, SpeexBits *bits)
+{
+   return (*((SpeexMode**)state))->enc(state, in, bits);
+}
+
+int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
+{
+   int i;
+   spx_int32_t N;
+   float float_in[MAX_IN_SAMPLES];
+   speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N);
+   for (i=0;i<N;i++)
+      float_in[i] = in[i];
+   return (*((SpeexMode**)state))->enc(state, float_in, bits);
+}
+
+int speex_decode(void *state, SpeexBits *bits, float *out)
+{
+   return (*((SpeexMode**)state))->dec(state, bits, out);
+}
+
+int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
+{
+   int i;
+   spx_int32_t N;
+   float float_out[MAX_IN_SAMPLES];
+   int ret;
+   speex_decoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N);
+   ret = (*((SpeexMode**)state))->dec(state, bits, float_out);
+   for (i=0;i<N;i++)
+   {
+      if (float_out[i]>32767.f)
+         out[i] = 32767;
+      else if (float_out[i]<-32768.f)
+         out[i] = -32768;
+      else
+         out[i] = (spx_int16_t)floor(.5+float_out[i]);
+   }
+   return ret;
+}
+#endif
+
+
+
+int speex_encoder_ctl(void *state, int request, void *ptr)
+{
+   return (*((SpeexMode**)state))->enc_ctl(state, request, ptr);
+}
+
+int speex_decoder_ctl(void *state, int request, void *ptr)
+{
+   return (*((SpeexMode**)state))->dec_ctl(state, request, ptr);
+}
+
+
+
+int nb_mode_query(const void *mode, int request, void *ptr)
+{
+   const SpeexNBMode *m = (const SpeexNBMode*)mode;
+   
+   switch (request)
+   {
+   case SPEEX_MODE_FRAME_SIZE:
+      *((int*)ptr)=m->frameSize;
+      break;
+   case SPEEX_SUBMODE_BITS_PER_FRAME:
+      if (*((int*)ptr)==0)
+         *((int*)ptr) = NB_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 nb_mode_query request: ", request);
+      return -1;
+   }
+   return 0;
+}
+
+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;
+}
+
+
+int speex_lib_ctl(int request, void *ptr)
+{
+   switch (request)
+   {
+      case SPEEX_LIB_GET_MAJOR_VERSION:
+         *((int*)ptr) = SPEEX_MAJOR_VERSION;
+         break;
+      case SPEEX_LIB_GET_MINOR_VERSION:
+         *((int*)ptr) = SPEEX_MINOR_VERSION;
+         break;
+      case SPEEX_LIB_GET_MICRO_VERSION:
+         *((int*)ptr) = SPEEX_MICRO_VERSION;
+         break;
+      case SPEEX_LIB_GET_EXTRA_VERSION:
+         *((const char**)ptr) = SPEEX_EXTRA_VERSION;
+         break;
+      case SPEEX_LIB_GET_VERSION_STRING:
+         *((const char**)ptr) = SPEEX_VERSION;
+         break;
+      /*case SPEEX_LIB_SET_ALLOC_FUNC:
+         break;
+      case SPEEX_LIB_GET_ALLOC_FUNC:
+         break;
+      case SPEEX_LIB_SET_FREE_FUNC:
+         break;
+      case SPEEX_LIB_GET_FREE_FUNC:
+         break;*/
+      default:
+         speex_warning_int("Unknown wb_mode_query request: ", request);
+         return -1;
+   }
+   return 0;
+}
diff --git a/3rdparty/speex/libspeex/speex_callbacks.c b/3rdparty/speex/libspeex/speex_callbacks.c
new file mode 100644
index 0000000..682322e
--- /dev/null
+++ b/3rdparty/speex/libspeex/speex_callbacks.c
@@ -0,0 +1,140 @@
+/* Copyright (C) 2002 Jean-Marc Valin
+   File speex_callbacks.c
+   Callback handling and in-band signalling
+
+
+   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 <speex/speex_callbacks.h>
+#include "misc.h"
+
+int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *state)
+{
+   int id;
+   SpeexCallback *callback;
+   /*speex_bits_advance(bits, 5);*/
+   id=speex_bits_unpack_unsigned(bits, 4);
+   callback = callback_list+id;
+
+   if (callback->func)
+   {
+      return callback->func(bits, state, callback->data);
+   } else
+      /*If callback is not registered, skip the right number of bits*/
+   {
+      int adv;
+      if (id<2)
+         adv = 1;
+      else if (id<8)
+         adv = 4;
+      else if (id<10)
+         adv = 8;
+      else if (id<12)
+         adv = 16;
+      else if (id<14)
+         adv = 32;
+      else 
+         adv = 64;
+      speex_bits_advance(bits, adv);
+   }
+   return 0;
+}
+
+int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data)
+{
+   spx_int32_t m;
+   m = speex_bits_unpack_unsigned(bits, 4);
+   speex_encoder_ctl(data, SPEEX_SET_MODE, &m);
+   return 0;
+}
+
+int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data)
+{
+   spx_int32_t m;
+   m = speex_bits_unpack_unsigned(bits, 4);
+   speex_encoder_ctl(data, SPEEX_SET_LOW_MODE, &m);
+   return 0;
+}
+
+int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data)
+{
+   spx_int32_t m;
+   m = speex_bits_unpack_unsigned(bits, 4);
+   speex_encoder_ctl(data, SPEEX_SET_HIGH_MODE, &m);
+   return 0;
+}
+
+int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data)
+{
+   spx_int32_t vbr;
+   vbr = speex_bits_unpack_unsigned(bits, 1);
+   speex_encoder_ctl(data, SPEEX_SET_VBR, &vbr);
+   return 0;
+}
+
+int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data)
+{
+   spx_int32_t enh;
+   enh = speex_bits_unpack_unsigned(bits, 1);
+   speex_decoder_ctl(data, SPEEX_SET_ENH, &enh);
+   return 0;
+}
+
+int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data)
+{
+   float qual;
+   qual = speex_bits_unpack_unsigned(bits, 4);
+   speex_encoder_ctl(data, SPEEX_SET_VBR_QUALITY, &qual);
+   return 0;
+}
+
+
+int speex_std_char_handler(SpeexBits *bits, void *state, void *data)
+{
+   unsigned char ch;
+   ch = speex_bits_unpack_unsigned(bits, 8);
+   _speex_putc(ch, data);
+   /*printf("speex_std_char_handler ch=%x\n", ch);*/
+   return 0;
+}
+
+
+
+/* Default handler for user callbacks: skip it */
+int speex_default_user_handler(SpeexBits *bits, void *state, void *data)
+{
+   int req_size = speex_bits_unpack_unsigned(bits, 4);
+   speex_bits_advance(bits, 5+8*req_size);
+   return 0;
+}
diff --git a/3rdparty/speex/libspeex/speex_header.c b/3rdparty/speex/libspeex/speex_header.c
new file mode 100644
index 0000000..8e10851
--- /dev/null
+++ b/3rdparty/speex/libspeex/speex_header.c
@@ -0,0 +1,166 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: speex_header.c
+   Describes the Speex header
+
+   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 "misc.h"
+#include <speex/speex_header.h>
+#include <speex/speex.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define ENDIAN_SWITCH(x) {x=le_int(x);}
+
+
+/*
+typedef struct SpeexHeader {
+   char speex_string[8];
+   char speex_version[SPEEX_HEADER_VERSION_LENGTH];
+   int speex_version_id;
+   int header_size;
+   int rate;
+   int mode;
+   int mode_bitstream_version;
+   int nb_channels;
+   int bitrate;
+   int frame_size;
+   int vbr;
+   int frames_per_packet;
+   int extra_headers;
+   int reserved1;
+   int reserved2;
+} SpeexHeader;
+*/
+
+void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const SpeexMode *m)
+{
+   int i;
+   const char *h="Speex   ";
+   /*
+   strncpy(header->speex_string, "Speex   ", 8);
+   strncpy(header->speex_version, SPEEX_VERSION, SPEEX_HEADER_VERSION_LENGTH-1);
+   header->speex_version[SPEEX_HEADER_VERSION_LENGTH-1]=0;
+   */
+   for (i=0;i<8;i++)
+      header->speex_string[i]=h[i];
+   for (i=0;i<SPEEX_HEADER_VERSION_LENGTH-1 && SPEEX_VERSION[i];i++)
+      header->speex_version[i]=SPEEX_VERSION[i];
+   for (;i<SPEEX_HEADER_VERSION_LENGTH;i++)
+      header->speex_version[i]=0;
+   
+   header->speex_version_id = 1;
+   header->header_size = sizeof(SpeexHeader);
+   
+   header->rate = rate;
+   header->mode = m->modeID;
+   header->mode_bitstream_version = m->bitstream_version;
+   if (m->modeID<0)
+      speex_warning("This mode is meant to be used alone");
+   header->nb_channels = nb_channels;
+   header->bitrate = -1;
+   speex_mode_query(m, SPEEX_MODE_FRAME_SIZE, &header->frame_size);
+   header->vbr = 0;
+   
+   header->frames_per_packet = 0;
+   header->extra_headers = 0;
+   header->reserved1 = 0;
+   header->reserved2 = 0;
+}
+
+char *speex_header_to_packet(SpeexHeader *header, int *size)
+{
+   SpeexHeader *le_header;
+   le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader));
+   
+   speex_move(le_header, header, sizeof(SpeexHeader));
+   
+   /*Make sure everything is now little-endian*/
+   ENDIAN_SWITCH(le_header->speex_version_id);
+   ENDIAN_SWITCH(le_header->header_size);
+   ENDIAN_SWITCH(le_header->rate);
+   ENDIAN_SWITCH(le_header->mode);
+   ENDIAN_SWITCH(le_header->mode_bitstream_version);
+   ENDIAN_SWITCH(le_header->nb_channels);
+   ENDIAN_SWITCH(le_header->bitrate);
+   ENDIAN_SWITCH(le_header->frame_size);
+   ENDIAN_SWITCH(le_header->vbr);
+   ENDIAN_SWITCH(le_header->frames_per_packet);
+   ENDIAN_SWITCH(le_header->extra_headers);
+
+   *size = sizeof(SpeexHeader);
+   return (char *)le_header;
+}
+
+SpeexHeader *speex_packet_to_header(char *packet, int size)
+{
+   int i;
+   SpeexHeader *le_header;
+   const char *h = "Speex   ";
+   for (i=0;i<8;i++)
+      if (packet[i]!=h[i])
+      {
+         speex_notify("This doesn't look like a Speex file");
+         return NULL;
+      }
+   
+   /*FIXME: Do we allow larger headers?*/
+   if (size < (int)sizeof(SpeexHeader))
+   {
+      speex_notify("Speex header too small");
+      return NULL;
+   }
+   
+   le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader));
+   
+   speex_move(le_header, packet, sizeof(SpeexHeader));
+   
+   /*Make sure everything is converted correctly from little-endian*/
+   ENDIAN_SWITCH(le_header->speex_version_id);
+   ENDIAN_SWITCH(le_header->header_size);
+   ENDIAN_SWITCH(le_header->rate);
+   ENDIAN_SWITCH(le_header->mode);
+   ENDIAN_SWITCH(le_header->mode_bitstream_version);
+   ENDIAN_SWITCH(le_header->nb_channels);
+   ENDIAN_SWITCH(le_header->bitrate);
+   ENDIAN_SWITCH(le_header->frame_size);
+   ENDIAN_SWITCH(le_header->vbr);
+   ENDIAN_SWITCH(le_header->frames_per_packet);
+   ENDIAN_SWITCH(le_header->extra_headers);
+
+   return le_header;
+
+}
diff --git a/3rdparty/speex/libspeex/stack_alloc.h b/3rdparty/speex/libspeex/stack_alloc.h
new file mode 100644
index 0000000..cb048fa
--- /dev/null
+++ b/3rdparty/speex/libspeex/stack_alloc.h
@@ -0,0 +1,124 @@
+/* Copyright (C) 2002 Jean-Marc Valin */
+/**
+   @file stack_alloc.h
+   @brief Temporary memory allocation on stack
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef STACK_ALLOC_H
+#define STACK_ALLOC_H
+
+#ifdef USE_ALLOCA
+#ifdef WIN32
+#include <malloc.h>
+#else
+#include <alloca.h>
+#endif
+#endif
+
+/**
+ * @def ALIGN(stack, size)
+ *
+ * Aligns the stack to a 'size' boundary
+ *
+ * @param stack Stack
+ * @param size  New size boundary
+ */
+
+/**
+ * @def PUSH(stack, size, type)
+ *
+ * Allocates 'size' elements of type 'type' on the stack
+ *
+ * @param stack Stack
+ * @param size  Number of elements
+ * @param type  Type of element
+ */
+
+/**
+ * @def PUSHS(stack, type)
+ *
+ * Allocates a struct stack 
+ *
+ * @param stack Stack
+ * @param type  Struct type
+ */
+
+/**
+ * @def VARDECL(var)
+ *
+ * Declare variable on stack
+ *
+ * @param var Variable to declare
+ */
+
+/**
+ * @def ALLOC(var, size, type)
+ *
+ * Allocate 'size' elements of 'type' on stack
+ *
+ * @param var  Name of variable to allocate
+ * @param size Number of elements
+ * @param type Type of element
+ */
+
+#ifdef ENABLE_VALGRIND
+
+#include <valgrind/memcheck.h>
+
+#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
+
+#define PUSH(stack, size, type) (VALGRIND_MAKE_NOACCESS(stack, 1000),ALIGN((stack),sizeof(type)),VALGRIND_MAKE_WRITABLE(stack, ((size)*sizeof(type))),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type))))
+
+#define PUSHS(stack, type) (VALGRIND_MAKE_NOACCESS(stack, 1000),ALIGN((stack),sizeof(long)),VALGRIND_MAKE_WRITABLE(stack, (sizeof(type))),(stack)+=(sizeof(type)),(type*)((stack)-(sizeof(type))))
+
+#else
+
+#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
+
+#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type))))
+
+#define PUSHS(stack, type) (ALIGN((stack),sizeof(long)),(stack)+=(sizeof(type)),(type*)((stack)-(sizeof(type))))
+
+#endif
+
+#if defined(VAR_ARRAYS)
+#define VARDECL(var) 
+#define ALLOC(var, size, type) type var[size]
+#elif defined(USE_ALLOCA)
+#define VARDECL(var) var
+#define ALLOC(var, size, type) var = alloca(sizeof(type)*(size))
+#else
+#define VARDECL(var) var
+#define ALLOC(var, size, type) var = PUSH(stack, size, type)
+#endif
+
+
+#endif
diff --git a/3rdparty/speex/libspeex/stereo.c b/3rdparty/speex/libspeex/stereo.c
new file mode 100644
index 0000000..f18387e
--- /dev/null
+++ b/3rdparty/speex/libspeex/stereo.c
@@ -0,0 +1,192 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: stereo.c
+
+   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 <speex/speex_stereo.h>
+#include <speex/speex_callbacks.h>
+#include "vq.h"
+#include <math.h>
+
+/*float e_ratio_quant[4] = {1, 1.26, 1.587, 2};*/
+static const float e_ratio_quant[4] = {.25f, .315f, .397f, .5f};
+
+void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits)
+{
+   int i, tmp;
+   float e_left=0, e_right=0, e_tot=0;
+   float balance, e_ratio;
+   for (i=0;i<frame_size;i++)
+   {
+      e_left  += ((float)data[2*i])*data[2*i];
+      e_right += ((float)data[2*i+1])*data[2*i+1];
+      data[i] =  .5*(((float)data[2*i])+data[2*i+1]);
+      e_tot   += ((float)data[i])*data[i];
+   }
+   balance=(e_left+1)/(e_right+1);
+   e_ratio = e_tot/(1+e_left+e_right);
+
+   /*Quantization*/
+   speex_bits_pack(bits, 14, 5);
+   speex_bits_pack(bits, SPEEX_INBAND_STEREO, 4);
+   
+   balance=4*log(balance);
+
+   /*Pack sign*/
+   if (balance>0)
+      speex_bits_pack(bits, 0, 1);
+   else
+      speex_bits_pack(bits, 1, 1);
+   balance=floor(.5+fabs(balance));
+   if (balance>30)
+      balance=31;
+   
+   speex_bits_pack(bits, (int)balance, 5);
+   
+   /*Quantize energy ratio*/
+   tmp=vq_index(&e_ratio, e_ratio_quant, 1, 4);
+   speex_bits_pack(bits, tmp, 2);
+}
+
+void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits)
+{
+   int i, tmp;
+   float e_left=0, e_right=0, e_tot=0;
+   float balance, e_ratio;
+   for (i=0;i<frame_size;i++)
+   {
+      e_left  += ((float)data[2*i])*data[2*i];
+      e_right += ((float)data[2*i+1])*data[2*i+1];
+      data[i] =  .5*(((float)data[2*i])+data[2*i+1]);
+      e_tot   += ((float)data[i])*data[i];
+   }
+   balance=(e_left+1)/(e_right+1);
+   e_ratio = e_tot/(1+e_left+e_right);
+
+   /*Quantization*/
+   speex_bits_pack(bits, 14, 5);
+   speex_bits_pack(bits, SPEEX_INBAND_STEREO, 4);
+   
+   balance=4*log(balance);
+
+   /*Pack sign*/
+   if (balance>0)
+      speex_bits_pack(bits, 0, 1);
+   else
+      speex_bits_pack(bits, 1, 1);
+   balance=floor(.5+fabs(balance));
+   if (balance>30)
+      balance=31;
+   
+   speex_bits_pack(bits, (int)balance, 5);
+   
+   /*Quantize energy ratio*/
+   tmp=vq_index(&e_ratio, e_ratio_quant, 1, 4);
+   speex_bits_pack(bits, tmp, 2);
+}
+
+void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *stereo)
+{
+   float balance, e_ratio;
+   int i;
+   float e_tot=0, e_left, e_right, e_sum;
+
+   balance=stereo->balance;
+   e_ratio=stereo->e_ratio;
+   for (i=frame_size-1;i>=0;i--)
+   {
+      e_tot += ((float)data[i])*data[i];
+   }
+   e_sum=e_tot/e_ratio;
+   e_left  = e_sum*balance / (1+balance);
+   e_right = e_sum-e_left;
+
+   e_left  = sqrt(e_left/(e_tot+.01));
+   e_right = sqrt(e_right/(e_tot+.01));
+
+   for (i=frame_size-1;i>=0;i--)
+   {
+      float ftmp=data[i];
+      stereo->smooth_left  = .98*stereo->smooth_left  + .02*e_left;
+      stereo->smooth_right = .98*stereo->smooth_right + .02*e_right;
+      data[2*i] = stereo->smooth_left*ftmp;
+      data[2*i+1] = stereo->smooth_right*ftmp;
+   }
+}
+
+void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState *stereo)
+{
+   float balance, e_ratio;
+   int i;
+   float e_tot=0, e_left, e_right, e_sum;
+
+   balance=stereo->balance;
+   e_ratio=stereo->e_ratio;
+   for (i=frame_size-1;i>=0;i--)
+   {
+      e_tot += ((float)data[i])*data[i];
+   }
+   e_sum=e_tot/e_ratio;
+   e_left  = e_sum*balance / (1+balance);
+   e_right = e_sum-e_left;
+
+   e_left  = sqrt(e_left/(e_tot+.01));
+   e_right = sqrt(e_right/(e_tot+.01));
+
+   for (i=frame_size-1;i>=0;i--)
+   {
+      float ftmp=data[i];
+      stereo->smooth_left  = .98*stereo->smooth_left  + .02*e_left;
+      stereo->smooth_right = .98*stereo->smooth_right + .02*e_right;
+      data[2*i] = stereo->smooth_left*ftmp;
+      data[2*i+1] = stereo->smooth_right*ftmp;
+   }
+}
+
+int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data)
+{
+   SpeexStereoState *stereo;
+   float sign=1;
+   int tmp;
+
+   stereo = (SpeexStereoState*)data;
+   if (speex_bits_unpack_unsigned(bits, 1))
+      sign=-1;
+   tmp = speex_bits_unpack_unsigned(bits, 5);
+   stereo->balance = exp(sign*.25*tmp);
+
+   tmp = speex_bits_unpack_unsigned(bits, 2);
+   stereo->e_ratio = e_ratio_quant[tmp];
+
+   return 0;
+}
diff --git a/3rdparty/speex/libspeex/testdenoise.c b/3rdparty/speex/libspeex/testdenoise.c
new file mode 100644
index 0000000..42644cb
--- /dev/null
+++ b/3rdparty/speex/libspeex/testdenoise.c
@@ -0,0 +1,44 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <speex/speex_preprocess.h>
+#include <stdio.h>
+
+#define NN 160
+
+int main()
+{
+   short in[NN];
+   int i;
+   SpeexPreprocessState *st;
+   int count=0;
+   float f;
+
+   st = speex_preprocess_state_init(NN, 8000);
+   i=1;
+   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DENOISE, &i);
+   i=0;
+   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC, &i);
+   f=8000;
+   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f);
+   i=0;
+   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB, &i);
+   f=.0;
+   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f);
+   f=.0;
+   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f);
+   while (1)
+   {
+      int vad;
+      fread(in, sizeof(short), NN, stdin);
+      if (feof(stdin))
+         break;
+      vad = speex_preprocess_run(st, in);
+      /*fprintf (stderr, "%d\n", vad);*/
+      fwrite(in, sizeof(short), NN, stdout);
+      count++;
+   }
+   speex_preprocess_state_destroy(st);
+   return 0;
+}
diff --git a/3rdparty/speex/libspeex/testecho.c b/3rdparty/speex/libspeex/testecho.c
new file mode 100644
index 0000000..7c32c8f
--- /dev/null
+++ b/3rdparty/speex/libspeex/testecho.c
@@ -0,0 +1,53 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "speex/speex_echo.h"
+#include "speex/speex_preprocess.h"
+
+
+#define NN 128
+#define TAIL 1024
+
+int main(int argc, char **argv)
+{
+   int echo_fd, ref_fd, e_fd;
+   short echo_buf[NN], ref_buf[NN], e_buf[NN];
+   SpeexEchoState *st;
+   SpeexPreprocessState *den;
+
+   if (argc != 4)
+   {
+      fprintf (stderr, "testecho mic_signal.sw speaker_signal.sw output.sw\n");
+      exit(1);
+   }
+   echo_fd = open (argv[2], O_RDONLY);
+   ref_fd  = open (argv[1],  O_RDONLY);
+   e_fd    = open (argv[3], O_WRONLY | O_CREAT | O_TRUNC, 0644);
+
+   st = speex_echo_state_init(NN, TAIL);
+   den = speex_preprocess_state_init(NN, 8000);
+   int tmp = 8000;
+   speex_echo_ctl(st, SPEEX_ECHO_SET_SAMPLING_RATE, &tmp);
+   speex_preprocess_ctl(den, SPEEX_PREPROCESS_SET_ECHO_STATE, st);
+
+   while (read(ref_fd, ref_buf, NN*2))
+   {
+      read(echo_fd, echo_buf, NN*2);
+      speex_echo_cancellation(st, ref_buf, echo_buf, e_buf);
+      speex_preprocess_run(den, e_buf);
+      write(e_fd, e_buf, NN*2);
+   }
+   speex_echo_state_destroy(st);
+   speex_preprocess_state_destroy(den);
+   close(e_fd);
+   close(echo_fd);
+   close(ref_fd);
+   return 0;
+}
diff --git a/3rdparty/speex/libspeex/testenc.c b/3rdparty/speex/libspeex/testenc.c
new file mode 100644
index 0000000..eabd02c
--- /dev/null
+++ b/3rdparty/speex/libspeex/testenc.c
@@ -0,0 +1,142 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <speex/speex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <speex/speex_callbacks.h>
+
+#ifdef FIXED_DEBUG
+extern long long spx_mips;
+#endif
+
+#define FRAME_SIZE 160
+#include <math.h>
+int main(int argc, char **argv)
+{
+   char *inFile, *outFile, *bitsFile;
+   FILE *fin, *fout, *fbits=NULL;
+   short in_short[FRAME_SIZE];
+   short out_short[FRAME_SIZE];
+   float sigpow,errpow,snr, seg_snr=0;
+   int snr_frames = 0;
+   char cbits[200];
+   int nbBits;
+   int i;
+   void *st;
+   void *dec;
+   SpeexBits bits;
+   spx_int32_t tmp;
+   int bitCount=0;
+   spx_int32_t skip_group_delay;
+   SpeexCallback callback;
+
+   sigpow = 0;
+   errpow = 0;
+
+   st = speex_encoder_init(&speex_nb_mode);
+   dec = speex_decoder_init(&speex_nb_mode);
+
+   /* BEGIN: You probably don't need the following in a real application */
+   callback.callback_id = SPEEX_INBAND_CHAR;
+   callback.func = speex_std_char_handler;
+   callback.data = stderr;
+   speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback);
+
+   callback.callback_id = SPEEX_INBAND_MODE_REQUEST;
+   callback.func = speex_std_mode_request_handler;
+   callback.data = st;
+   speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback);
+   /* END of unnecessary stuff */
+
+   tmp=1;
+   speex_decoder_ctl(dec, SPEEX_SET_ENH, &tmp);
+   tmp=0;
+   speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp);
+   tmp=8;
+   speex_encoder_ctl(st, SPEEX_SET_QUALITY, &tmp);
+   tmp=1;
+   speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp);
+
+   /* Turn this off if you want to measure SNR (on by default) */
+   tmp=1;
+   speex_encoder_ctl(st, SPEEX_SET_HIGHPASS, &tmp);
+   speex_decoder_ctl(dec, SPEEX_SET_HIGHPASS, &tmp);
+
+   speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &skip_group_delay);
+   speex_decoder_ctl(dec, SPEEX_GET_LOOKAHEAD, &tmp);
+   skip_group_delay += tmp;
+
+   if (argc != 4 && argc != 3)
+   {
+      fprintf (stderr, "Usage: encode [in file] [out file] [bits file]\nargc = %d", argc);
+      exit(1);
+   }
+   inFile = argv[1];
+   fin = fopen(inFile, "r");
+   outFile = argv[2];
+   fout = fopen(outFile, "w+");
+   if (argc==4)
+   {
+      bitsFile = argv[3];
+      fbits = fopen(bitsFile, "w");
+   }
+   speex_bits_init(&bits);
+   while (!feof(fin))
+   {
+      fread(in_short, sizeof(short), FRAME_SIZE, fin);
+      if (feof(fin))
+         break;
+      speex_bits_reset(&bits);
+
+      speex_encode_int(st, in_short, &bits);
+      nbBits = speex_bits_write(&bits, cbits, 200);
+      bitCount+=bits.nbBits;
+
+      if (argc==4)
+         fwrite(cbits, 1, nbBits, fbits);
+      speex_bits_rewind(&bits);
+
+      speex_decode_int(dec, &bits, out_short);
+      speex_bits_reset(&bits);
+
+      fwrite(&out_short[skip_group_delay], sizeof(short), FRAME_SIZE-skip_group_delay, fout);
+      skip_group_delay = 0;
+   }
+   fprintf (stderr, "Total encoded size: %d bits\n", bitCount);
+   speex_encoder_destroy(st);
+   speex_decoder_destroy(dec);
+   speex_bits_destroy(&bits);
+
+   /* This code just computes SNR, so you don't need it either */
+   rewind(fin);
+   rewind(fout);
+
+   while ( FRAME_SIZE == fread(in_short, sizeof(short), FRAME_SIZE, fin) 
+           &&
+           FRAME_SIZE ==  fread(out_short, sizeof(short), FRAME_SIZE,fout) )
+   {
+	float s=0, e=0;
+        for (i=0;i<FRAME_SIZE;++i) {
+            s += (float)in_short[i] * in_short[i];
+            e += ((float)in_short[i]-out_short[i]) * ((float)in_short[i]-out_short[i]);
+        }
+	seg_snr += 10*log10((s+160)/(e+160));
+	sigpow += s;
+	errpow += e;
+	snr_frames++;
+   }
+   fclose(fin);
+   fclose(fout);
+
+   snr = 10 * log10( sigpow / errpow );
+   seg_snr /= snr_frames;
+   fprintf(stderr,"SNR = %f\nsegmental SNR = %f\n",snr, seg_snr);
+
+#ifdef FIXED_DEBUG
+   printf ("Total: %f MIPS\n", (float)(1e-6*50*spx_mips/snr_frames));
+#endif
+   
+   return 0;
+}
diff --git a/3rdparty/speex/libspeex/testenc_uwb.c b/3rdparty/speex/libspeex/testenc_uwb.c
new file mode 100644
index 0000000..e9bf18a
--- /dev/null
+++ b/3rdparty/speex/libspeex/testenc_uwb.c
@@ -0,0 +1,137 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <speex/speex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <speex/speex_callbacks.h>
+
+#ifdef FIXED_DEBUG
+extern long long spx_mips;
+#endif
+
+#define FRAME_SIZE 640
+#include <math.h>
+int main(int argc, char **argv)
+{
+   char *inFile, *outFile, *bitsFile;
+   FILE *fin, *fout, *fbits=NULL;
+   short in_short[FRAME_SIZE];
+   short out_short[FRAME_SIZE];
+   float in_float[FRAME_SIZE];
+   float sigpow,errpow,snr, seg_snr=0;
+   int snr_frames = 0;
+   char cbits[200];
+   int nbBits;
+   int i;
+   void *st;
+   void *dec;
+   SpeexBits bits;
+   spx_int32_t tmp;
+   int bitCount=0;
+   spx_int32_t skip_group_delay;
+   SpeexCallback callback;
+
+   sigpow = 0;
+   errpow = 0;
+
+   st = speex_encoder_init(&speex_uwb_mode);
+   dec = speex_decoder_init(&speex_uwb_mode);
+
+   callback.callback_id = SPEEX_INBAND_CHAR;
+   callback.func = speex_std_char_handler;
+   callback.data = stderr;
+   speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback);
+
+   callback.callback_id = SPEEX_INBAND_MODE_REQUEST;
+   callback.func = speex_std_mode_request_handler;
+   callback.data = st;
+   speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback);
+
+   tmp=0;
+   speex_decoder_ctl(dec, SPEEX_SET_ENH, &tmp);
+   tmp=0;
+   speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp);
+   tmp=7;
+   speex_encoder_ctl(st, SPEEX_SET_QUALITY, &tmp);
+   tmp=1;
+   speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp);
+
+   speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &skip_group_delay);
+   speex_decoder_ctl(dec, SPEEX_GET_LOOKAHEAD, &tmp);
+   skip_group_delay += tmp;
+
+
+   if (argc != 4 && argc != 3)
+   {
+      fprintf (stderr, "Usage: encode [in file] [out file] [bits file]\nargc = %d", argc);
+      exit(1);
+   }
+   inFile = argv[1];
+   fin = fopen(inFile, "r");
+   outFile = argv[2];
+   fout = fopen(outFile, "w+");
+   if (argc==4)
+   {
+      bitsFile = argv[3];
+      fbits = fopen(bitsFile, "w");
+   }
+   speex_bits_init(&bits);
+   while (!feof(fin))
+   {
+      fread(in_short, sizeof(short), FRAME_SIZE, fin);
+      if (feof(fin))
+         break;
+      for (i=0;i<FRAME_SIZE;i++)
+         in_float[i]=in_short[i];
+      speex_bits_reset(&bits);
+
+      speex_encode_int(st, in_short, &bits);
+      nbBits = speex_bits_write(&bits, cbits, 200);
+      bitCount+=bits.nbBits;
+
+      if (argc==4)
+         fwrite(cbits, 1, nbBits, fbits);
+      speex_bits_rewind(&bits);
+
+      speex_decode_int(dec, &bits, out_short);
+      speex_bits_reset(&bits);
+
+      fwrite(&out_short[skip_group_delay], sizeof(short), FRAME_SIZE-skip_group_delay, fout);
+      skip_group_delay = 0;
+   }
+   fprintf (stderr, "Total encoded size: %d bits\n", bitCount);
+   speex_encoder_destroy(st);
+   speex_decoder_destroy(dec);
+
+   rewind(fin);
+   rewind(fout);
+
+   while ( FRAME_SIZE == fread(in_short, sizeof(short), FRAME_SIZE, fin) 
+           &&
+           FRAME_SIZE ==  fread(out_short, sizeof(short), FRAME_SIZE,fout) )
+   {
+	float s=0, e=0;
+        for (i=0;i<FRAME_SIZE;++i) {
+            s += (float)in_short[i] * in_short[i];
+            e += ((float)in_short[i]-out_short[i]) * ((float)in_short[i]-out_short[i]);
+        }
+	seg_snr += 10*log10((s+1)/(e+1));
+	sigpow += s;
+	errpow += e;
+	snr_frames++;
+   }
+   fclose(fin);
+   fclose(fout);
+
+   snr = 10 * log10( sigpow / errpow );
+   seg_snr /= snr_frames;
+   fprintf(stderr,"SNR = %f\nsegmental SNR = %f\n",snr, seg_snr);
+
+#ifdef FIXED_DEBUG
+   printf ("Total: %f MIPS\n", (float)(1e-6*50*spx_mips/snr_frames));
+#endif
+   
+   return 1;
+}
diff --git a/3rdparty/speex/libspeex/testenc_wb.c b/3rdparty/speex/libspeex/testenc_wb.c
new file mode 100644
index 0000000..8e515cb
--- /dev/null
+++ b/3rdparty/speex/libspeex/testenc_wb.c
@@ -0,0 +1,143 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <speex/speex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <speex/speex_callbacks.h>
+
+#ifdef FIXED_DEBUG
+extern long long spx_mips;
+#endif
+
+#define FRAME_SIZE 320
+#include <math.h>
+int main(int argc, char **argv)
+{
+   char *inFile, *outFile, *bitsFile;
+   FILE *fin, *fout, *fbits=NULL;
+   short in_short[FRAME_SIZE];
+   short out_short[FRAME_SIZE];
+   float in_float[FRAME_SIZE];
+   float sigpow,errpow,snr, seg_snr=0;
+   int snr_frames = 0;
+   char cbits[200];
+   int nbBits;
+   int i;
+   void *st;
+   void *dec;
+   SpeexBits bits;
+   spx_int32_t tmp;
+   int bitCount=0;
+   spx_int32_t skip_group_delay;
+   SpeexCallback callback;
+
+   sigpow = 0;
+   errpow = 0;
+
+   st = speex_encoder_init(&speex_wb_mode);
+   dec = speex_decoder_init(&speex_wb_mode);
+
+   callback.callback_id = SPEEX_INBAND_CHAR;
+   callback.func = speex_std_char_handler;
+   callback.data = stderr;
+   speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback);
+
+   callback.callback_id = SPEEX_INBAND_MODE_REQUEST;
+   callback.func = speex_std_mode_request_handler;
+   callback.data = st;
+   speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback);
+
+   tmp=1;
+   speex_decoder_ctl(dec, SPEEX_SET_ENH, &tmp);
+   tmp=0;
+   speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp);
+   tmp=8;
+   speex_encoder_ctl(st, SPEEX_SET_QUALITY, &tmp);
+   tmp=3;
+   speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp);
+   /*tmp=3;
+   speex_encoder_ctl(st, SPEEX_SET_HIGH_MODE, &tmp);
+   tmp=6;
+   speex_encoder_ctl(st, SPEEX_SET_LOW_MODE, &tmp);
+*/
+
+   speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &skip_group_delay);
+   speex_decoder_ctl(dec, SPEEX_GET_LOOKAHEAD, &tmp);
+   skip_group_delay += tmp;
+
+
+   if (argc != 4 && argc != 3)
+   {
+      fprintf (stderr, "Usage: encode [in file] [out file] [bits file]\nargc = %d", argc);
+      exit(1);
+   }
+   inFile = argv[1];
+   fin = fopen(inFile, "r");
+   outFile = argv[2];
+   fout = fopen(outFile, "w+");
+   if (argc==4)
+   {
+      bitsFile = argv[3];
+      fbits = fopen(bitsFile, "w");
+   }
+   speex_bits_init(&bits);
+   while (!feof(fin))
+   {
+      fread(in_short, sizeof(short), FRAME_SIZE, fin);
+      if (feof(fin))
+         break;
+      for (i=0;i<FRAME_SIZE;i++)
+         in_float[i]=in_short[i];
+      speex_bits_reset(&bits);
+
+      speex_encode_int(st, in_short, &bits);
+      nbBits = speex_bits_write(&bits, cbits, 200);
+      bitCount+=bits.nbBits;
+
+      if (argc==4)
+         fwrite(cbits, 1, nbBits, fbits);
+      speex_bits_rewind(&bits);
+
+      speex_decode_int(dec, &bits, out_short);
+      speex_bits_reset(&bits);
+
+      fwrite(&out_short[skip_group_delay], sizeof(short), FRAME_SIZE-skip_group_delay, fout);
+      skip_group_delay = 0;
+   }
+   fprintf (stderr, "Total encoded size: %d bits\n", bitCount);
+   speex_encoder_destroy(st);
+   speex_decoder_destroy(dec);
+   speex_bits_destroy(&bits);
+
+   rewind(fin);
+   rewind(fout);
+
+   while ( FRAME_SIZE == fread(in_short, sizeof(short), FRAME_SIZE, fin) 
+           &&
+           FRAME_SIZE ==  fread(out_short, sizeof(short), FRAME_SIZE,fout) )
+   {
+	float s=0, e=0;
+        for (i=0;i<FRAME_SIZE;++i) {
+            s += (float)in_short[i] * in_short[i];
+            e += ((float)in_short[i]-out_short[i]) * ((float)in_short[i]-out_short[i]);
+        }
+	seg_snr += 10*log10((s+160)/(e+160));
+	sigpow += s;
+	errpow += e;
+	snr_frames++;
+   }
+   fclose(fin);
+   fclose(fout);
+
+   snr = 10 * log10( sigpow / errpow );
+   seg_snr /= snr_frames;
+   fprintf(stderr,"SNR = %f\nsegmental SNR = %f\n",snr, seg_snr);
+
+#ifdef FIXED_DEBUG
+   printf ("Total: %f MIPS\n", (float)(1e-6*50*spx_mips/snr_frames));
+#endif
+   
+   return 1;
+}
diff --git a/3rdparty/speex/libspeex/testresample.c b/3rdparty/speex/libspeex/testresample.c
new file mode 100644
index 0000000..5e02479
--- /dev/null
+++ b/3rdparty/speex/libspeex/testresample.c
@@ -0,0 +1,86 @@
+/* Copyright (C) 2007 Jean-Marc Valin
+      
+   File: testresample.c
+   Testing the resampling code
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are
+   met:
+
+   1. Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+   DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include "speex/speex_resampler.h"
+#include <math.h>
+#include <stdlib.h>
+
+#define NN 256
+
+int main(int argc, char **argv)
+{
+   int i;
+   short *in;
+   short *out;
+   float *fin, *fout;
+   int count = 0;
+   SpeexResamplerState *st = speex_resampler_init(1, 8000, 12000, 10);
+   speex_resampler_set_rate(st, 8000, 15999);
+   speex_resampler_skip_zeros(st);
+   
+   in = malloc(NN*sizeof(short));
+   out = malloc(2*NN*sizeof(short));
+   fin = malloc(NN*sizeof(float));
+   fout = malloc(2*NN*sizeof(float));
+   while (1)
+   {
+      int in_len;
+      int out_len;
+      fread(in, sizeof(short), NN, stdin);
+      if (feof(stdin))
+         break;
+      for (i=0;i<NN;i++)
+         fin[i]=in[i];
+      in_len = NN;
+      out_len = 2*NN;
+      /*if (count==2)
+         speex_resampler_set_quality(st, 10);*/
+      speex_resampler_process_float(st, 0, fin, &in_len, fout, &out_len);
+      for (i=0;i<out_len;i++)
+         out[i]=floor(.5+fout[i]);
+      /*speex_warning_int("writing", out_len);*/
+      fwrite(out, sizeof(short), out_len, stdout);
+      count++;
+   }
+   speex_resampler_destroy(st);
+   free(in);
+   free(out);
+   free(fin);
+   free(fout);
+   return 0;
+}
+
diff --git a/3rdparty/speex/libspeex/vbr.c b/3rdparty/speex/libspeex/vbr.c
new file mode 100644
index 0000000..d24ec0f
--- /dev/null
+++ b/3rdparty/speex/libspeex/vbr.c
@@ -0,0 +1,272 @@
+/* Copyright (C) 2002 Jean-Marc Valin 
+   File: vbr.c
+
+   VBR-related routines
+
+   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 "vbr.h"
+#include <math.h>
+
+
+#define sqr(x) ((x)*(x))
+
+#define MIN_ENERGY 6000
+#define NOISE_POW .3
+
+
+const float vbr_nb_thresh[9][11]={
+   {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /*   CNG   */
+   { 3.5f,  2.5f,  2.0f,  1.2f,  0.5f,  0.0f, -0.5f, -0.7f, -0.8f, -0.9f, -1.0f}, /*  2 kbps */
+   {10.0f,  6.5f,  5.2f,  4.5f,  3.9f,  3.5f,  3.0f,  2.5f,  2.3f,  1.8f,  1.0f}, /*  6 kbps */
+   {11.0f,  8.8f,  7.5f,  6.5f,  5.0f,  3.9f,  3.9f,  3.9f,  3.5f,  3.0f,  1.0f}, /*  8 kbps */
+   {11.0f, 11.0f,  9.9f,  9.0f,  8.0f,  7.0f,  6.5f,  6.0f,  5.0f,  4.0f,  2.0f}, /* 11 kbps */
+   {11.0f, 11.0f, 11.0f, 11.0f,  9.5f,  9.0f,  8.0f,  7.0f,  6.5f,  5.0f,  3.0f}, /* 15 kbps */
+   {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f,  9.5f,  8.5f,  8.0f,  6.5f,  4.0f}, /* 18 kbps */
+   {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f,  9.8f,  7.5f,  5.5f}, /* 24 kbps */ 
+   { 8.0f,  5.0f,  3.7f,  3.0f,  2.5f,  2.0f,  1.8f,  1.5f,  1.0f,  0.0f,  0.0f}  /*  4 kbps */
+};
+
+
+const float vbr_hb_thresh[5][11]={
+   {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /* silence */
+   {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /*  2 kbps */
+   {11.0f, 11.0f,  9.5f,  8.5f,  7.5f,  6.0f,  5.0f,  3.9f,  3.0f,  2.0f,  1.0f}, /*  6 kbps */
+   {11.0f, 11.0f, 11.0f, 11.0f, 11.0f,  9.5f,  8.7f,  7.8f,  7.0f,  6.5f,  4.0f}, /* 10 kbps */
+   {11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f, 11.0f,  9.8f,  7.5f,  5.5f}  /* 18 kbps */ 
+};
+
+const float vbr_uhb_thresh[2][11]={
+   {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}, /* silence */
+   { 3.9f,  2.5f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f, -1.0f}  /*  2 kbps */
+};
+
+void vbr_init(VBRState *vbr)
+{
+   int i;
+
+   vbr->average_energy=0;
+   vbr->last_energy=1;
+   vbr->accum_sum=0;
+   vbr->energy_alpha=.1;
+   vbr->soft_pitch=0;
+   vbr->last_pitch_coef=0;
+   vbr->last_quality=0;
+
+   vbr->noise_accum = .05*pow(MIN_ENERGY, NOISE_POW);
+   vbr->noise_accum_count=.05;
+   vbr->noise_level=vbr->noise_accum/vbr->noise_accum_count;
+   vbr->consec_noise=0;
+
+
+   for (i=0;i<VBR_MEMORY_SIZE;i++)
+      vbr->last_log_energy[i] = log(MIN_ENERGY);
+}
+
+
+/*
+  This function should analyse the signal and decide how critical the
+  coding error will be perceptually. The following factors should be
+  taken into account:
+
+  -Attacks (positive energy derivative) should be coded with more bits
+
+  -Stationary voiced segments should receive more bits
+
+  -Segments with (very) low absolute energy should receive less bits (maybe
+  only shaped noise?)
+
+  -DTX for near-zero energy?
+
+  -Stationary fricative segments should have less bits
+
+  -Temporal masking: when energy slope is decreasing, decrease the bit-rate
+
+  -Decrease bit-rate for males (low pitch)?
+
+  -(wideband only) less bits in the high-band when signal is very 
+  non-stationary (harder to notice high-frequency noise)???
+
+*/
+
+float vbr_analysis(VBRState *vbr, spx_word16_t *sig, int len, int pitch, float pitch_coef)
+{
+   int i;
+   float ener=0, ener1=0, ener2=0;
+   float qual=7;
+   int va;
+   float log_energy;
+   float non_st=0;
+   float voicing;
+   float pow_ener;
+
+   for (i=0;i<len>>1;i++)
+      ener1 += ((float)sig[i])*sig[i];
+
+   for (i=len>>1;i<len;i++)
+      ener2 += ((float)sig[i])*sig[i];
+   ener=ener1+ener2;
+
+   log_energy = log(ener+MIN_ENERGY);
+   for (i=0;i<VBR_MEMORY_SIZE;i++)
+      non_st += sqr(log_energy-vbr->last_log_energy[i]);
+   non_st =  non_st/(30*VBR_MEMORY_SIZE);
+   if (non_st>1)
+      non_st=1;
+
+   voicing = 3*(pitch_coef-.4)*fabs(pitch_coef-.4);
+   vbr->average_energy = (1-vbr->energy_alpha)*vbr->average_energy + vbr->energy_alpha*ener;
+   vbr->noise_level=vbr->noise_accum/vbr->noise_accum_count;
+   pow_ener = pow(ener,NOISE_POW);
+   if (vbr->noise_accum_count<.06 && ener>MIN_ENERGY)
+      vbr->noise_accum = .05*pow_ener;
+
+   if ((voicing<.3 && non_st < .2 && pow_ener < 1.2*vbr->noise_level)
+       || (voicing<.3 && non_st < .05 && pow_ener < 1.5*vbr->noise_level)
+       || (voicing<.4 && non_st < .05 && pow_ener < 1.2*vbr->noise_level)
+       || (voicing<0 && non_st < .05))
+   {
+      float tmp;
+      va = 0;
+      vbr->consec_noise++;
+      if (pow_ener > 3*vbr->noise_level)
+         tmp = 3*vbr->noise_level;
+      else 
+         tmp = pow_ener;
+      if (vbr->consec_noise>=4)
+      {
+         vbr->noise_accum = .95*vbr->noise_accum + .05*tmp;
+         vbr->noise_accum_count = .95*vbr->noise_accum_count + .05;
+      }
+   } else {
+      va = 1;
+      vbr->consec_noise=0;
+   }
+
+   if (pow_ener < vbr->noise_level && ener>MIN_ENERGY)
+   {
+      vbr->noise_accum = .95*vbr->noise_accum + .05*pow_ener;
+      vbr->noise_accum_count = .95*vbr->noise_accum_count + .05;      
+   }
+
+   /* Checking for very low absolute energy */
+   if (ener < 30000)
+   {
+      qual -= .7;
+      if (ener < 10000)
+         qual-=.7;
+      if (ener < 3000)
+         qual-=.7;
+   } else {
+      float short_diff, long_diff;
+      short_diff = log((ener+1)/(1+vbr->last_energy));
+      long_diff = log((ener+1)/(1+vbr->average_energy));
+      /*fprintf (stderr, "%f %f\n", short_diff, long_diff);*/
+
+      if (long_diff<-5)
+         long_diff=-5;
+      if (long_diff>2)
+         long_diff=2;
+
+      if (long_diff>0)
+         qual += .6*long_diff;
+      if (long_diff<0)
+         qual += .5*long_diff;
+      if (short_diff>0)
+      {
+         if (short_diff>5)
+            short_diff=5;
+         qual += .5*short_diff;
+      }
+      /* Checking for energy increases */
+      if (ener2 > 1.6*ener1)
+         qual += .5;
+   }
+   vbr->last_energy = ener;
+   vbr->soft_pitch = .6*vbr->soft_pitch + .4*pitch_coef;
+   qual += 2.2*((pitch_coef-.4) + (vbr->soft_pitch-.4));
+
+   if (qual < vbr->last_quality)
+      qual = .5*qual + .5*vbr->last_quality;
+   if (qual<4)
+      qual=4;
+   if (qual>10)
+      qual=10;
+   
+   /*
+   if (vbr->consec_noise>=2)
+      qual-=1.3;
+   if (vbr->consec_noise>=5)
+      qual-=1.3;
+   if (vbr->consec_noise>=12)
+      qual-=1.3;
+   */
+   if (vbr->consec_noise>=3)
+      qual=4;
+
+   if (vbr->consec_noise)
+      qual -= 1.0 * (log(3.0 + vbr->consec_noise)-log(3));
+   if (qual<0)
+      qual=0;
+   
+   if (ener<60000)
+   {
+      if (vbr->consec_noise>2)
+         qual-=0.5*(log(3.0 + vbr->consec_noise)-log(3));
+      if (ener<10000&&vbr->consec_noise>2)
+         qual-=0.5*(log(3.0 + vbr->consec_noise)-log(3));
+      if (qual<0)
+         qual=0;
+      qual += .3*log(.0001+ener/60000.0);
+   }
+   if (qual<-1)
+      qual=-1;
+
+   /*printf ("%f %f %f %f %d\n", qual, voicing, non_st, pow_ener/(.01+vbr->noise_level), va);*/
+
+   vbr->last_pitch_coef = pitch_coef;
+   vbr->last_quality = qual;
+
+   for (i=VBR_MEMORY_SIZE-1;i>0;i--)
+      vbr->last_log_energy[i] = vbr->last_log_energy[i-1];
+   vbr->last_log_energy[0] = log_energy;
+
+   /*printf ("VBR: %f %f %f %d %f\n", (float)(log_energy-log(vbr->average_energy+MIN_ENERGY)), non_st, voicing, va, vbr->noise_level);*/
+
+   return qual;
+}
+
+void vbr_destroy(VBRState *vbr)
+{
+}
diff --git a/3rdparty/speex/libspeex/vbr.h b/3rdparty/speex/libspeex/vbr.h
new file mode 100644
index 0000000..34e1d4c
--- /dev/null
+++ b/3rdparty/speex/libspeex/vbr.h
@@ -0,0 +1,70 @@
+/* Copyright (C) 2002 Jean-Marc Valin */
+/**
+   @file vbr.h
+   @brief Variable Bit-Rate (VBR) related routines
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+
+#ifndef VBR_H
+#define VBR_H
+
+#include "misc.h"
+
+#define VBR_MEMORY_SIZE 5
+
+extern const float vbr_nb_thresh[9][11];
+extern const float vbr_hb_thresh[5][11];
+extern const float vbr_uhb_thresh[2][11];
+
+/** VBR state. */
+typedef struct VBRState {
+   float energy_alpha;
+   float average_energy;
+   float last_energy;
+   float last_log_energy[VBR_MEMORY_SIZE];
+   float accum_sum;
+   float last_pitch_coef;
+   float soft_pitch;
+   float last_quality;
+   float noise_level;
+   float noise_accum;
+   float noise_accum_count;
+   int   consec_noise;
+} VBRState;
+
+void vbr_init(VBRState *vbr);
+
+float vbr_analysis(VBRState *vbr, spx_word16_t *sig, int len, int pitch, float pitch_coef);
+
+void vbr_destroy(VBRState *vbr);
+
+#endif
diff --git a/3rdparty/speex/libspeex/vorbis_psy.c b/3rdparty/speex/libspeex/vorbis_psy.c
new file mode 100644
index 0000000..6aac56f
--- /dev/null
+++ b/3rdparty/speex/libspeex/vorbis_psy.c
@@ -0,0 +1,508 @@
+/* Copyright (C) 2005 Jean-Marc Valin, CSIRO, Christopher Montgomery
+   File: vorbis_psy.c
+
+   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
+
+#ifdef VORBIS_PSYCHO
+
+#include "misc.h"
+#include "smallft.h"
+#include "lpc.h"
+#include "vorbis_psy.h"
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+/* psychoacoustic setup ********************************************/
+
+static VorbisPsyInfo example_tuning = {
+  
+  .5,.5,  
+  3,3,25,
+  
+  /*63     125     250     500      1k      2k      4k      8k     16k*/
+  // vorbis mode 4 style
+  //{-32,-32,-32,-32,-28,-24,-22,-20,-20, -20, -20, -8, -6, -6, -6, -6, -6},
+  { -4, -6, -6, -6, -6, -6, -6, -6, -8, -8,-10,-10, -8, -6, -4, -4, -2},
+  
+  {
+    0, 1, 2, 3, 4, 5, 5,  5,     /* 7dB */
+    6, 6, 6, 5, 4, 4, 4,  4,     /* 15dB */
+    4, 4, 5, 5, 5, 6, 6,  6,     /* 23dB */
+    7, 7, 7, 8, 8, 8, 9, 10,     /* 31dB */
+    11,12,13,14,15,16,17, 18,     /* 39dB */
+  }
+
+};
+
+
+
+/* there was no great place to put this.... */
+#include <stdio.h>
+static void _analysis_output(char *base,int i,float *v,int n,int bark,int dB){
+  int j;
+  FILE *of;
+  char buffer[80];
+
+  sprintf(buffer,"%s_%d.m",base,i);
+  of=fopen(buffer,"w");
+  
+  if(!of)perror("failed to open data dump file");
+  
+  for(j=0;j<n;j++){
+    if(bark){
+      float b=toBARK((4000.f*j/n)+.25);
+      fprintf(of,"%f ",b);
+    }else
+      fprintf(of,"%f ",(double)j);
+    
+    if(dB){
+      float val;
+      if(v[j]==0.)
+	val=-140.;
+      else
+	val=todB(v[j]);
+      fprintf(of,"%f\n",val);
+    }else{
+      fprintf(of,"%f\n",v[j]);
+    }
+  }
+  fclose(of);
+}
+
+static void bark_noise_hybridmp(int n,const long *b,
+                                const float *f,
+                                float *noise,
+                                const float offset,
+                                const int fixed){
+  
+  float *N=alloca(n*sizeof(*N));
+  float *X=alloca(n*sizeof(*N));
+  float *XX=alloca(n*sizeof(*N));
+  float *Y=alloca(n*sizeof(*N));
+  float *XY=alloca(n*sizeof(*N));
+
+  float tN, tX, tXX, tY, tXY;
+  int i;
+
+  int lo, hi;
+  float R, A, B, D;
+  float w, x, y;
+
+  tN = tX = tXX = tY = tXY = 0.f;
+
+  y = f[0] + offset;
+  if (y < 1.f) y = 1.f;
+
+  w = y * y * .5;
+    
+  tN += w;
+  tX += w;
+  tY += w * y;
+
+  N[0] = tN;
+  X[0] = tX;
+  XX[0] = tXX;
+  Y[0] = tY;
+  XY[0] = tXY;
+
+  for (i = 1, x = 1.f; i < n; i++, x += 1.f) {
+    
+    y = f[i] + offset;
+    if (y < 1.f) y = 1.f;
+
+    w = y * y;
+    
+    tN += w;
+    tX += w * x;
+    tXX += w * x * x;
+    tY += w * y;
+    tXY += w * x * y;
+
+    N[i] = tN;
+    X[i] = tX;
+    XX[i] = tXX;
+    Y[i] = tY;
+    XY[i] = tXY;
+  }
+  
+  for (i = 0, x = 0.f;; i++, x += 1.f) {
+    
+    lo = b[i] >> 16;
+    if( lo>=0 ) break;
+    hi = b[i] & 0xffff;
+    
+    tN = N[hi] + N[-lo];
+    tX = X[hi] - X[-lo];
+    tXX = XX[hi] + XX[-lo];
+    tY = Y[hi] + Y[-lo];    
+    tXY = XY[hi] - XY[-lo];
+    
+    A = tY * tXX - tX * tXY;
+    B = tN * tXY - tX * tY;
+    D = tN * tXX - tX * tX;
+    R = (A + x * B) / D;
+    if (R < 0.f)
+      R = 0.f;
+    
+    noise[i] = R - offset;
+  }
+  
+  for ( ;; i++, x += 1.f) {
+    
+    lo = b[i] >> 16;
+    hi = b[i] & 0xffff;
+    if(hi>=n)break;
+    
+    tN = N[hi] - N[lo];
+    tX = X[hi] - X[lo];
+    tXX = XX[hi] - XX[lo];
+    tY = Y[hi] - Y[lo];
+    tXY = XY[hi] - XY[lo];
+    
+    A = tY * tXX - tX * tXY;
+    B = tN * tXY - tX * tY;
+    D = tN * tXX - tX * tX;
+    R = (A + x * B) / D;
+    if (R < 0.f) R = 0.f;
+    
+    noise[i] = R - offset;
+  }
+  for ( ; i < n; i++, x += 1.f) {
+    
+    R = (A + x * B) / D;
+    if (R < 0.f) R = 0.f;
+    
+    noise[i] = R - offset;
+  }
+  
+  if (fixed <= 0) return;
+  
+  for (i = 0, x = 0.f;; i++, x += 1.f) {
+    hi = i + fixed / 2;
+    lo = hi - fixed;
+    if(lo>=0)break;
+
+    tN = N[hi] + N[-lo];
+    tX = X[hi] - X[-lo];
+    tXX = XX[hi] + XX[-lo];
+    tY = Y[hi] + Y[-lo];
+    tXY = XY[hi] - XY[-lo];
+    
+    
+    A = tY * tXX - tX * tXY;
+    B = tN * tXY - tX * tY;
+    D = tN * tXX - tX * tX;
+    R = (A + x * B) / D;
+
+    if (R - offset < noise[i]) noise[i] = R - offset;
+  }
+  for ( ;; i++, x += 1.f) {
+    
+    hi = i + fixed / 2;
+    lo = hi - fixed;
+    if(hi>=n)break;
+    
+    tN = N[hi] - N[lo];
+    tX = X[hi] - X[lo];
+    tXX = XX[hi] - XX[lo];
+    tY = Y[hi] - Y[lo];
+    tXY = XY[hi] - XY[lo];
+    
+    A = tY * tXX - tX * tXY;
+    B = tN * tXY - tX * tY;
+    D = tN * tXX - tX * tX;
+    R = (A + x * B) / D;
+    
+    if (R - offset < noise[i]) noise[i] = R - offset;
+  }
+  for ( ; i < n; i++, x += 1.f) {
+    R = (A + x * B) / D;
+    if (R - offset < noise[i]) noise[i] = R - offset;
+  }
+}
+
+static void _vp_noisemask(VorbisPsy *p,
+			  float *logfreq, 
+			  float *logmask){
+
+  int i,n=p->n/2;
+  float *work=alloca(n*sizeof(*work));
+
+  bark_noise_hybridmp(n,p->bark,logfreq,logmask,
+		      140.,-1);
+
+  for(i=0;i<n;i++)work[i]=logfreq[i]-logmask[i];
+
+  bark_noise_hybridmp(n,p->bark,work,logmask,0.,
+		      p->vi->noisewindowfixed);
+
+  for(i=0;i<n;i++)work[i]=logfreq[i]-work[i];
+  
+  {
+    static int seq=0;
+    
+    float work2[n];
+    for(i=0;i<n;i++){
+      work2[i]=logmask[i]+work[i];
+    }
+    
+    //_analysis_output("logfreq",seq,logfreq,n,0,0);
+    //_analysis_output("median",seq,work,n,0,0);
+    //_analysis_output("envelope",seq,work2,n,0,0);
+    seq++;
+  }
+
+  for(i=0;i<n;i++){
+    int dB=logmask[i]+.5;
+    if(dB>=NOISE_COMPAND_LEVELS)dB=NOISE_COMPAND_LEVELS-1;
+    if(dB<0)dB=0;
+    logmask[i]= work[i]+p->vi->noisecompand[dB]+p->noiseoffset[i];
+  }
+
+}
+
+VorbisPsy *vorbis_psy_init(int rate, int n)
+{
+  long i,j,lo=-99,hi=1;
+  VorbisPsy *p = speex_alloc(sizeof(VorbisPsy));
+  memset(p,0,sizeof(*p));
+  
+  p->n = n;
+  spx_drft_init(&p->lookup, n);
+  p->bark = speex_alloc(n*sizeof(*p->bark));
+  p->rate=rate;
+  p->vi = &example_tuning;
+
+  /* BH4 window */
+  p->window = speex_alloc(sizeof(*p->window)*n);
+  float a0 = .35875f;
+  float a1 = .48829f;
+  float a2 = .14128f;
+  float a3 = .01168f;
+  for(i=0;i<n;i++)
+    p->window[i] = //a0 - a1*cos(2.*M_PI/n*(i+.5)) + a2*cos(4.*M_PI/n*(i+.5)) - a3*cos(6.*M_PI/n*(i+.5));
+      sin((i+.5)/n * M_PI)*sin((i+.5)/n * M_PI);
+  /* bark scale lookups */
+  for(i=0;i<n;i++){
+    float bark=toBARK(rate/(2*n)*i); 
+    
+    for(;lo+p->vi->noisewindowlomin<i && 
+	  toBARK(rate/(2*n)*lo)<(bark-p->vi->noisewindowlo);lo++);
+    
+    for(;hi<=n && (hi<i+p->vi->noisewindowhimin ||
+	  toBARK(rate/(2*n)*hi)<(bark+p->vi->noisewindowhi));hi++);
+    
+    p->bark[i]=((lo-1)<<16)+(hi-1);
+
+  }
+
+  /* set up rolling noise median */
+  p->noiseoffset=speex_alloc(n*sizeof(*p->noiseoffset));
+  
+  for(i=0;i<n;i++){
+    float halfoc=toOC((i+.5)*rate/(2.*n))*2.;
+    int inthalfoc;
+    float del;
+    
+    if(halfoc<0)halfoc=0;
+    if(halfoc>=P_BANDS-1)halfoc=P_BANDS-1;
+    inthalfoc=(int)halfoc;
+    del=halfoc-inthalfoc;
+    
+    p->noiseoffset[i]=
+      p->vi->noiseoff[inthalfoc]*(1.-del) + 
+      p->vi->noiseoff[inthalfoc+1]*del;
+    
+  }
+#if 0
+  _analysis_output_always("noiseoff0",ls,p->noiseoffset,n,1,0,0);
+#endif
+
+   return p;
+}
+
+void vorbis_psy_destroy(VorbisPsy *p)
+{
+  if(p){
+    spx_drft_clear(&p->lookup);
+    if(p->bark)
+      speex_free(p->bark);
+    if(p->noiseoffset)
+      speex_free(p->noiseoffset);
+    if(p->window)
+      speex_free(p->window);
+    memset(p,0,sizeof(*p));
+    speex_free(p);
+  }
+}
+
+void compute_curve(VorbisPsy *psy, float *audio, float *curve)
+{
+   int i;
+   float work[psy->n];
+
+   float scale=4.f/psy->n;
+   float scale_dB;
+
+   scale_dB=todB(scale);
+  
+   /* window the PCM data; use a BH4 window, not vorbis */
+   for(i=0;i<psy->n;i++)
+     work[i]=audio[i] * psy->window[i];
+
+   {
+     static int seq=0;
+     
+     //_analysis_output("win",seq,work,psy->n,0,0);
+
+     seq++;
+   }
+
+    /* FFT yields more accurate tonal estimation (not phase sensitive) */
+    spx_drft_forward(&psy->lookup,work);
+
+    /* magnitudes */
+    work[0]=scale_dB+todB(work[0]);
+    for(i=1;i<psy->n-1;i+=2){
+      float temp = work[i]*work[i] + work[i+1]*work[i+1];
+      work[(i+1)>>1] = scale_dB+.5f * todB(temp);
+    }
+
+    /* derive a noise curve */
+    _vp_noisemask(psy,work,curve);
+#define SIDEL 12
+    for (i=0;i<SIDEL;i++)
+    {
+       curve[i]=curve[SIDEL];
+    }
+#define SIDEH 12
+    for (i=0;i<SIDEH;i++)
+    {
+       curve[(psy->n>>1)-i-1]=curve[(psy->n>>1)-SIDEH];
+    }
+    for(i=0;i<((psy->n)>>1);i++)
+       curve[i] = fromdB(1.2*curve[i]+.2*i);
+       //curve[i] = fromdB(0.8*curve[i]+.35*i);
+       //curve[i] = fromdB(0.9*curve[i])*pow(1.0*i+45,1.3);
+}
+
+/* Transform a masking curve (power spectrum) into a pole-zero filter */
+void curve_to_lpc(VorbisPsy *psy, float *curve, float *awk1, float *awk2, int ord)
+{
+   int i;
+   float ac[psy->n];
+   float tmp;
+   int len = psy->n >> 1;
+   for (i=0;i<2*len;i++)
+      ac[i] = 0;
+   for (i=1;i<len;i++)
+      ac[2*i-1] = curve[i];
+   ac[0] = curve[0];
+   ac[2*len-1] = curve[len-1];
+   
+   spx_drft_backward(&psy->lookup, ac);
+   _spx_lpc(awk1, ac, ord);
+   tmp = 1.;
+   for (i=0;i<ord;i++)
+   {
+      tmp *= .99;
+      awk1[i] *= tmp;
+   }
+#if 0
+   for (i=0;i<ord;i++)
+      awk2[i] = 0;
+#else
+   /* Use the second (awk2) filter to correct the first one */
+   for (i=0;i<2*len;i++)
+      ac[i] = 0;   
+   for (i=0;i<ord;i++)
+      ac[i+1] = awk1[i];
+   ac[0] = 1;
+   spx_drft_forward(&psy->lookup, ac);
+   /* Compute (power) response of awk1 (all zero) */
+   ac[0] *= ac[0];
+   for (i=1;i<len;i++)
+      ac[i] = ac[2*i-1]*ac[2*i-1] + ac[2*i]*ac[2*i];
+   ac[len] = ac[2*len-1]*ac[2*len-1];
+   /* Compute correction required */
+   for (i=0;i<len;i++)
+      curve[i] = 1. / (1e-6f+curve[i]*ac[i]);
+
+   for (i=0;i<2*len;i++)
+      ac[i] = 0;
+   for (i=1;i<len;i++)
+      ac[2*i-1] = curve[i];
+   ac[0] = curve[0];
+   ac[2*len-1] = curve[len-1];
+   
+   spx_drft_backward(&psy->lookup, ac);
+   _spx_lpc(awk2, ac, ord);
+   tmp = 1;
+   for (i=0;i<ord;i++)
+   {
+      tmp *= .99;
+      awk2[i] *= tmp;
+   }
+#endif
+}
+
+#if 0
+#include <stdio.h>
+#include <math.h>
+
+#define ORDER 10
+#define CURVE_SIZE 24
+
+int main()
+{
+   int i;
+   float curve[CURVE_SIZE];
+   float awk1[ORDER], awk2[ORDER];
+   for (i=0;i<CURVE_SIZE;i++)
+      scanf("%f ", &curve[i]);
+   for (i=0;i<CURVE_SIZE;i++)
+      curve[i] = pow(10.f, .1*curve[i]);
+   curve_to_lpc(curve, CURVE_SIZE, awk1, awk2, ORDER);
+   for (i=0;i<ORDER;i++)
+      printf("%f ", awk1[i]);
+   printf ("\n");
+   for (i=0;i<ORDER;i++)
+      printf("%f ", awk2[i]);
+   printf ("\n");
+   return 0;
+}
+#endif
+
+#endif
diff --git a/3rdparty/speex/libspeex/vorbis_psy.h b/3rdparty/speex/libspeex/vorbis_psy.h
new file mode 100644
index 0000000..fbdb7c5
--- /dev/null
+++ b/3rdparty/speex/libspeex/vorbis_psy.h
@@ -0,0 +1,97 @@
+/* Copyright (C) 2005 Jean-Marc Valin, CSIRO, Christopher Montgomery
+   File: vorbis_psy.h
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VORBIS_PSY_H
+#define VORBIS_PSY_H
+
+#ifdef VORBIS_PSYCHO
+
+#include "smallft.h"
+#define P_BANDS 17      /* 62Hz to 16kHz */
+#define NOISE_COMPAND_LEVELS 40
+
+
+#define todB(x)   ((x)==0?-400.f:log((x)*(x))*4.34294480f)
+#define fromdB(x) (exp((x)*.11512925f))  
+
+/* The bark scale equations are approximations, since the original
+   table was somewhat hand rolled.  The below are chosen to have the
+   best possible fit to the rolled tables, thus their somewhat odd
+   appearance (these are more accurate and over a longer range than
+   the oft-quoted bark equations found in the texts I have).  The
+   approximations are valid from 0 - 30kHz (nyquist) or so.
+
+   all f in Hz, z in Bark */
+
+#define toBARK(n)   (13.1f*atan(.00074f*(n))+2.24f*atan((n)*(n)*1.85e-8f)+1e-4f*(n))
+#define fromBARK(z) (102.f*(z)-2.f*pow(z,2.f)+.4f*pow(z,3.f)+pow(1.46f,z)-1.f)
+
+/* Frequency to octave.  We arbitrarily declare 63.5 Hz to be octave
+   0.0 */
+
+#define toOC(n)     (log(n)*1.442695f-5.965784f)
+#define fromOC(o)   (exp(((o)+5.965784f)*.693147f))
+
+
+typedef struct {
+
+  float noisewindowlo;
+  float noisewindowhi;
+  int   noisewindowlomin;
+  int   noisewindowhimin;
+  int   noisewindowfixed;
+  float noiseoff[P_BANDS];
+  float noisecompand[NOISE_COMPAND_LEVELS];
+
+} VorbisPsyInfo;
+
+
+
+typedef struct {
+  int n;
+  int rate;
+  struct drft_lookup lookup;
+  VorbisPsyInfo *vi;
+
+  float *window;
+  float *noiseoffset;
+  long  *bark;
+
+} VorbisPsy;
+
+
+VorbisPsy *vorbis_psy_init(int rate, int size);
+void vorbis_psy_destroy(VorbisPsy *psy);
+void compute_curve(VorbisPsy *psy, float *audio, float *curve);
+void curve_to_lpc(VorbisPsy *psy, float *curve, float *awk1, float *awk2, int ord);
+
+#endif
+#endif
diff --git a/3rdparty/speex/libspeex/vq.c b/3rdparty/speex/libspeex/vq.c
new file mode 100644
index 0000000..d40133f
--- /dev/null
+++ b/3rdparty/speex/libspeex/vq.c
@@ -0,0 +1,170 @@
+/* Copyright (C) 2002 Jean-Marc Valin
+   File: vq.c
+   Vector quantization
+
+   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 "vq.h"
+#include "stack_alloc.h"
+#include "misc.h"
+
+#ifdef _USE_SSE
+#include <xmmintrin.h>
+#include "vq_sse.h"
+#elif defined(SHORTCUTS) && (defined(ARM4_ASM) || defined(ARM5E_ASM))
+#include "vq_arm4.h"
+#elif defined(BFIN_ASM)
+#include "vq_bfin.h"
+#endif
+
+
+int scal_quant(spx_word16_t in, const spx_word16_t *boundary, int entries)
+{
+   int i=0;
+   while (i<entries-1 && in>boundary[0])
+   {
+      boundary++;
+      i++;
+   }
+   return i;
+}
+
+int scal_quant32(spx_word32_t in, const spx_word32_t *boundary, int entries)
+{
+   int i=0;
+   while (i<entries-1 && in>boundary[0])
+   {
+      boundary++;
+      i++;
+   }
+   return i;
+}
+
+/*Finds the index of the entry in a codebook that best matches the input*/
+int vq_index(float *in, const float *codebook, int len, int entries)
+{
+   int i,j;
+   float min_dist=0;
+   int best_index=0;
+   for (i=0;i<entries;i++)
+   {
+      float dist=0;
+      for (j=0;j<len;j++)
+      {
+         float tmp = in[j]-*codebook++;
+         dist += tmp*tmp;
+      }
+      if (i==0 || dist<min_dist)
+      {
+         min_dist=dist;
+         best_index=i;
+      }
+   }
+   return best_index;
+}
+
+
+#ifndef OVERRIDE_VQ_NBEST
+/*Finds the indices of the n-best entries in a codebook*/
+void vq_nbest(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack)
+{
+   int i,j,k,used;
+   used = 0;
+   for (i=0;i<entries;i++)
+   {
+      spx_word32_t dist=0;
+      for (j=0;j<len;j++)
+         dist = MAC16_16(dist,in[j],*codebook++);
+#ifdef FIXED_POINT
+      dist=SUB32(SHR32(E[i],1),dist);
+#else
+      dist=.5f*E[i]-dist;
+#endif
+      if (i<N || dist<best_dist[N-1])
+      {
+         for (k=N-1; (k >= 1) && (k > used || dist < best_dist[k-1]); k--)
+         {
+            best_dist[k]=best_dist[k-1];
+            nbest[k] = nbest[k-1];
+         }
+         best_dist[k]=dist;
+         nbest[k]=i;
+         used++;
+      }
+   }
+}
+#endif
+
+
+
+
+#ifndef OVERRIDE_VQ_NBEST_SIGN
+/*Finds the indices of the n-best entries in a codebook with sign*/
+void vq_nbest_sign(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack)
+{
+   int i,j,k, sign, used;
+   used=0;
+   for (i=0;i<entries;i++)
+   {
+      spx_word32_t dist=0;
+      for (j=0;j<len;j++)
+         dist = MAC16_16(dist,in[j],*codebook++);
+      if (dist>0)
+      {
+         sign=0;
+         dist=-dist;
+      } else
+      {
+         sign=1;
+      }
+#ifdef FIXED_POINT
+      dist = ADD32(dist,SHR32(E[i],1));
+#else
+      dist = ADD32(dist,.5f*E[i]);
+#endif
+      if (i<N || dist<best_dist[N-1])
+      {
+         for (k=N-1; (k >= 1) && (k > used || dist < best_dist[k-1]); k--)
+         {
+            best_dist[k]=best_dist[k-1];
+            nbest[k] = nbest[k-1];
+         }
+         best_dist[k]=dist;
+         nbest[k]=i;
+         used++;
+         if (sign)
+            nbest[k]+=entries;
+      }
+   }
+}
+#endif
diff --git a/3rdparty/speex/libspeex/vq.h b/3rdparty/speex/libspeex/vq.h
new file mode 100644
index 0000000..7ca8197
--- /dev/null
+++ b/3rdparty/speex/libspeex/vq.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 2002 Jean-Marc Valin */
+/**
+   @file vq.h
+   @brief Vector quantization
+*/
+/*
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VQ_H
+#define VQ_H
+
+#include "misc.h"
+
+int scal_quant(spx_word16_t in, const spx_word16_t *boundary, int entries);
+int scal_quant32(spx_word32_t in, const spx_word32_t *boundary, int entries);
+
+int vq_index(float *in, const float *codebook, int len, int entries);
+#ifdef _USE_SSE
+#include <xmmintrin.h>
+void vq_nbest(spx_word16_t *in, const __m128 *codebook, int len, int entries, __m128 *E, int N, int *nbest, spx_word32_t *best_dist, char *stack);
+
+void vq_nbest_sign(spx_word16_t *in, const __m128 *codebook, int len, int entries, __m128 *E, int N, int *nbest, spx_word32_t *best_dist, char *stack);
+#else
+void vq_nbest(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack);
+
+void vq_nbest_sign(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack);
+#endif
+
+#endif
diff --git a/3rdparty/speex/libspeex/vq_arm4.h b/3rdparty/speex/libspeex/vq_arm4.h
new file mode 100644
index 0000000..585b861
--- /dev/null
+++ b/3rdparty/speex/libspeex/vq_arm4.h
@@ -0,0 +1,115 @@
+/* Copyright (C) 2004 Jean-Marc Valin */
+/**
+   @file vq_arm4.h
+   @brief ARM4-optimized vq routine
+*/
+/*
+   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.
+*/
+
+#define OVERRIDE_VQ_NBEST
+void vq_nbest(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack)
+{
+   int i,j;
+   for (i=0;i<entries;i+=4)
+   {
+#if 1
+      spx_word32_t dist1, dist2, dist3, dist4;
+      int dead1, dead2, dead3, dead4, dead5, dead6, dead7, dead8;
+      __asm__ __volatile__ (
+            "mov %0, #0 \n\t"
+            "mov %1, #0 \n\t"
+            "mov %2, #0 \n\t"
+            "mov %3, #0 \n\t"
+            "mov %10, %4 \n\t"
+            "add %4, %4, %4\n\t"
+            ".vqloop%=:\n\t"
+            "ldrsh %7, [%5], #2 \n\t"
+            "ldrsh %8, [%6] \n\t"
+            "mov %9, %6 \n\t"
+            "mla %0, %7, %8, %0 \n\t"
+            "ldrsh %8, [%9, %4]! \n\t"
+            "mla %1, %7, %8, %1 \n\t"
+            "ldrsh %8, [%9, %4]!\n\t"
+            "mla %2, %7, %8, %2 \n\t"
+            "ldrsh %8, [%9, %4]! \n\t"
+            "mla %3, %7, %8, %3 \n\t"
+            "subs %10, %10, #1 \n\t"
+            "add %6, %6, #2 \n\t"
+            "bne .vqloop%="
+         : "=r" (dist1), "=r" (dist2), "=r" (dist3), "=r" (dist4),
+      "=r" (dead1), "=r" (dead2), "=r" (codebook), "=r" (dead4),
+      "=r" (dead5), "=r" (dead6), "=r" (dead7)
+         : "4" (len), "5" (in), "6" (codebook)
+         : "cc");
+#else
+dist1=dist2=dist3=dist4=0;
+   /*   spx_word32_t dist1=0;
+      spx_word32_t dist2=0;
+      spx_word32_t dist3=0;
+      spx_word32_t dist4=0;*/
+      for (j=0;j<2;j++)
+      {
+         const spx_word16_t *code = codebook;
+         dist1 = MAC16_16(dist1,in[j],*code);
+         code += len;
+         dist2 = MAC16_16(dist2,in[j],*code);
+         code += len;
+         dist3 = MAC16_16(dist3,in[j],*code);
+         code += len;
+         dist4 = MAC16_16(dist4,in[j],*code);
+         codebook++;
+      }
+#endif
+      dist1=SUB32(SHR(*E++,1),dist1);
+      if (dist1<*best_dist || i==0)
+      {
+         *best_dist=dist1;
+         *nbest=i;
+      }
+      dist2=SUB32(SHR(*E++,1),dist2);
+      if (dist2<*best_dist)
+      {
+         *best_dist=dist2;
+         *nbest=i+1;
+      }
+      dist3=SUB32(SHR(*E++,1),dist3);
+      if (dist3<*best_dist)
+      {
+         *best_dist=dist3;
+         *nbest=i+2;
+      }
+      dist4=SUB32(SHR(*E++,1),dist4);
+      if (dist4<*best_dist)
+      {
+         *best_dist=dist4;
+         *nbest=i+3;
+      }
+      codebook += 3*len;
+   }
+}
diff --git a/3rdparty/speex/libspeex/vq_bfin.h b/3rdparty/speex/libspeex/vq_bfin.h
new file mode 100644
index 0000000..2cc9ea5
--- /dev/null
+++ b/3rdparty/speex/libspeex/vq_bfin.h
@@ -0,0 +1,107 @@
+/* Copyright (C) 2005 Analog Devices */
+/**
+   @file vq_bfin.h
+   @author Jean-Marc Valin 
+   @brief Blackfin-optimized vq routine
+*/
+/*
+   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.
+*/
+
+#define OVERRIDE_VQ_NBEST
+void vq_nbest(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack)
+{
+   if (N==1)
+   {
+      best_dist[0] = 2147483647;
+      {
+         spx_word32_t dist;
+         __asm__ __volatile__
+               (
+            "LC0 = %8;\n\t"
+            "R2 = 0;\n\t"
+            "I0 = %6;\n\t"
+            "B0 = %6;\n\t"
+            "L0 = %9;\n\t"
+            "LOOP entries_loop%= LC0;\n\t"
+            "LOOP_BEGIN entries_loop%=;\n\t"
+               "%0 = [%4++];\n\t"
+               "%0 >>= 1;\n\t"
+               "A0 = %0;\n\t"
+               "R0.L = W[%1++%7] || R1.L = W[I0++];\n\t"
+               "LOOP vq_loop%= LC1 = %5;\n\t"
+               "LOOP_BEGIN vq_loop%=;\n\t"
+                  "%0 = (A0 -= R0.L*R1.L) (IS) || R0.L = W[%1++%7] || R1.L = W[I0++];\n\t"
+               "LOOP_END vq_loop%=;\n\t"
+               "%0 = (A0 -= R0.L*R1.L) (IS);\n\t"
+               "cc = %0 < %2;\n\t"
+               "if cc %2 = %0;\n\t"
+               "if cc %3 = R2;\n\t"
+               "R2 += 1;\n\t"
+            "LOOP_END entries_loop%=;\n\t"
+            : "=&D" (dist), "=&a" (codebook), "=&d" (best_dist[0]), "=&d" (nbest[0]), "=&a" (E)
+            : "a" (len-1), "a" (in), "a" (2), "d" (entries), "d" (len<<1), "1" (codebook), "4" (E), "2" (best_dist[0]), "3" (nbest[0])
+            : "R0", "R1", "R2", "I0", "L0", "B0", "A0", "cc", "memory"
+               );
+      }
+   } else {
+   int i,k,used;
+   used = 0;
+   for (i=0;i<entries;i++)
+   {
+      spx_word32_t dist;
+      __asm__
+            (
+            "%0 >>= 1;\n\t"
+            "A0 = %0;\n\t"
+            "I0 = %3;\n\t"
+            "L0 = 0;\n\t"
+            "R0.L = W[%1++%4] || R1.L = W[I0++];\n\t"
+            "LOOP vq_loop%= LC0 = %2;\n\t"
+            "LOOP_BEGIN vq_loop%=;\n\t"
+               "%0 = (A0 -= R0.L*R1.L) (IS) || R0.L = W[%1++%4] || R1.L = W[I0++];\n\t"
+            "LOOP_END vq_loop%=;\n\t"
+            "%0 = (A0 -= R0.L*R1.L) (IS);\n\t"
+         : "=D" (dist), "=a" (codebook)
+         : "a" (len-1), "a" (in), "a" (2), "1" (codebook), "0" (E[i])
+         : "R0", "R1", "I0", "L0", "A0"
+            );
+      if (i<N || dist<best_dist[N-1])
+      {
+         for (k=N-1; (k >= 1) && (k > used || dist < best_dist[k-1]); k--)
+         {
+            best_dist[k]=best_dist[k-1];
+            nbest[k] = nbest[k-1];
+         }
+         best_dist[k]=dist;
+         nbest[k]=i;
+         used++;
+      }
+   }
+   }
+}
diff --git a/3rdparty/speex/libspeex/vq_sse.h b/3rdparty/speex/libspeex/vq_sse.h
new file mode 100644
index 0000000..00a42ce
--- /dev/null
+++ b/3rdparty/speex/libspeex/vq_sse.h
@@ -0,0 +1,120 @@
+/* Copyright (C) 2004 Jean-Marc Valin */
+/**
+   @file vq_sse.h
+   @brief SSE-optimized vq routine
+*/
+/*
+   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.
+*/
+
+#define OVERRIDE_VQ_NBEST
+void vq_nbest(spx_word16_t *_in, const __m128 *codebook, int len, int entries, __m128 *E, int N, int *nbest, spx_word32_t *best_dist, char *stack)
+{
+   int i,j,k,used;
+   VARDECL(float *dist);
+   VARDECL(__m128 *in);
+   __m128 half;
+   used = 0;
+   ALLOC(dist, entries, float);
+   half = _mm_set_ps1(.5f);
+   ALLOC(in, len, __m128);
+   for (i=0;i<len;i++)
+      in[i] = _mm_set_ps1(_in[i]);
+   for (i=0;i<entries>>2;i++)
+   {
+      __m128 d = _mm_mul_ps(E[i], half);
+      for (j=0;j<len;j++)
+         d = _mm_sub_ps(d, _mm_mul_ps(in[j], *codebook++));
+      _mm_storeu_ps(dist+4*i, d);
+   }
+   for (i=0;i<entries;i++)
+   {
+      if (i<N || dist[i]<best_dist[N-1])
+      {
+         for (k=N-1; (k >= 1) && (k > used || dist[i] < best_dist[k-1]); k--)
+         {
+            best_dist[k]=best_dist[k-1];
+            nbest[k] = nbest[k-1];
+         }
+         best_dist[k]=dist[i];
+         nbest[k]=i;
+         used++;
+      }
+   }
+}
+
+
+
+
+#define OVERRIDE_VQ_NBEST_SIGN
+void vq_nbest_sign(spx_word16_t *_in, const __m128 *codebook, int len, int entries, __m128 *E, int N, int *nbest, spx_word32_t *best_dist, char *stack)
+{
+   int i,j,k,used;
+   VARDECL(float *dist);
+   VARDECL(__m128 *in);
+   __m128 half;
+   used = 0;
+   ALLOC(dist, entries, float);
+   half = _mm_set_ps1(.5f);
+   ALLOC(in, len, __m128);
+   for (i=0;i<len;i++)
+      in[i] = _mm_set_ps1(_in[i]);
+   for (i=0;i<entries>>2;i++)
+   {
+      __m128 d = _mm_setzero_ps();
+      for (j=0;j<len;j++)
+         d = _mm_add_ps(d, _mm_mul_ps(in[j], *codebook++));
+      _mm_storeu_ps(dist+4*i, d);
+   }
+   for (i=0;i<entries;i++)
+   {
+      int sign;
+      if (dist[i]>0)
+      {
+         sign=0;
+         dist[i]=-dist[i];
+      } else
+      {
+         sign=1;
+      }
+      dist[i] += .5f*((float*)E)[i];
+      if (i<N || dist[i]<best_dist[N-1])
+      {
+         for (k=N-1; (k >= 1) && (k > used || dist[i] < best_dist[k-1]); k--)
+         {
+            best_dist[k]=best_dist[k-1];
+            nbest[k] = nbest[k-1];
+         }
+         best_dist[k]=dist[i];
+         nbest[k]=i;
+         used++;
+         if (sign)
+            nbest[k]+=entries;
+      }
+   }
+}
diff --git a/3rdparty/speex/libspeex/window.c b/3rdparty/speex/libspeex/window.c
new file mode 100644
index 0000000..65b1917
--- /dev/null
+++ b/3rdparty/speex/libspeex/window.c
@@ -0,0 +1,94 @@
+/* Copyright (C) 2006 Jean-Marc Valin 
+   File: window.c
+
+   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 "misc.h"
+
+#ifdef FIXED_POINT
+const spx_word16_t lpc_window[200] = {
+1310, 1313, 1321, 1333, 1352, 1375, 1403, 1436,
+1475, 1518, 1567, 1621, 1679, 1743, 1811, 1884,
+1962, 2044, 2132, 2224, 2320, 2421, 2526, 2636,
+2750, 2868, 2990, 3116, 3246, 3380, 3518, 3659,
+3804, 3952, 4104, 4259, 4417, 4578, 4742, 4909,
+5079, 5251, 5425, 5602, 5781, 5963, 6146, 6331,
+6518, 6706, 6896, 7087, 7280, 7473, 7668, 7863,
+8059, 8256, 8452, 8650, 8847, 9044, 9241, 9438,
+9635, 9831, 10026, 10220, 10414, 10606, 10797, 10987,
+11176, 11363, 11548, 11731, 11912, 12091, 12268, 12443,
+12615, 12785, 12952, 13116, 13277, 13435, 13590, 13742,
+13890, 14035, 14176, 14314, 14448, 14578, 14704, 14826,
+14944, 15058, 15168, 15273, 15374, 15470, 15562, 15649,
+15732, 15810, 15883, 15951, 16015, 16073, 16127, 16175,
+16219, 16257, 16291, 16319, 16342, 16360, 16373, 16381,
+16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
+16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
+16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
+16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
+16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
+16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
+16384, 16384, 16384, 16361, 16294, 16183, 16028, 15830,
+15588, 15304, 14979, 14613, 14207, 13763, 13282, 12766,
+12215, 11631, 11016, 10373, 9702, 9007, 8289, 7551,
+6797, 6028, 5251, 4470, 3695, 2943, 2248, 1696
+};
+#else
+const spx_word16_t lpc_window[200] = {
+   0.080000f, 0.080158f, 0.080630f, 0.081418f, 0.082520f, 0.083935f, 0.085663f, 0.087703f,
+   0.090052f, 0.092710f, 0.095674f, 0.098943f, 0.102514f, 0.106385f, 0.110553f, 0.115015f,
+   0.119769f, 0.124811f, 0.130137f, 0.135744f, 0.141628f, 0.147786f, 0.154212f, 0.160902f,
+   0.167852f, 0.175057f, 0.182513f, 0.190213f, 0.198153f, 0.206328f, 0.214731f, 0.223357f,
+   0.232200f, 0.241254f, 0.250513f, 0.259970f, 0.269619f, 0.279453f, 0.289466f, 0.299651f,
+   0.310000f, 0.320507f, 0.331164f, 0.341965f, 0.352901f, 0.363966f, 0.375151f, 0.386449f,
+   0.397852f, 0.409353f, 0.420943f, 0.432615f, 0.444361f, 0.456172f, 0.468040f, 0.479958f,
+   0.491917f, 0.503909f, 0.515925f, 0.527959f, 0.540000f, 0.552041f, 0.564075f, 0.576091f,
+   0.588083f, 0.600042f, 0.611960f, 0.623828f, 0.635639f, 0.647385f, 0.659057f, 0.670647f,
+   0.682148f, 0.693551f, 0.704849f, 0.716034f, 0.727099f, 0.738035f, 0.748836f, 0.759493f,
+   0.770000f, 0.780349f, 0.790534f, 0.800547f, 0.810381f, 0.820030f, 0.829487f, 0.838746f,
+   0.847800f, 0.856643f, 0.865269f, 0.873672f, 0.881847f, 0.889787f, 0.897487f, 0.904943f,
+   0.912148f, 0.919098f, 0.925788f, 0.932214f, 0.938372f, 0.944256f, 0.949863f, 0.955189f,
+   0.960231f, 0.964985f, 0.969447f, 0.973615f, 0.977486f, 0.981057f, 0.984326f, 0.987290f,
+   0.989948f, 0.992297f, 0.994337f, 0.996065f, 0.997480f, 0.998582f, 0.999370f, 0.999842f,
+   1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+   1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+   1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+   1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+   1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+   1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+   1.000000f, 1.000000f, 1.000000f, 0.998640f, 0.994566f, 0.987787f, 0.978324f, 0.966203f,
+   0.951458f, 0.934131f, 0.914270f, 0.891931f, 0.867179f, 0.840084f, 0.810723f, 0.779182f,
+   0.745551f, 0.709930f, 0.672424f, 0.633148f, 0.592223f, 0.549781f, 0.505964f, 0.460932f,
+   0.414863f, 0.367968f, 0.320511f, 0.272858f, 0.225569f, 0.179655f, 0.137254f, 0.103524f
+};
+#endif