[FFmpeg-devel] [PATCH] avcodec: add native Speex decoder

Paul B Mahol onemda at gmail.com
Tue Sep 21 01:33:40 EEST 2021


Signed-off-by: Paul B Mahol <onemda at gmail.com>
---
 libavcodec/Makefile    |    1 +
 libavcodec/allcodecs.c |    1 +
 libavcodec/speexdata.h |  780 ++++++++++++++++++++
 libavcodec/speexdec.c  | 1584 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 2366 insertions(+)
 create mode 100644 libavcodec/speexdata.h
 create mode 100644 libavcodec/speexdec.c

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 11873eecae..7a603e44dd 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -632,6 +632,7 @@ OBJS-$(CONFIG_SONIC_ENCODER)           += sonic.o
 OBJS-$(CONFIG_SONIC_LS_ENCODER)        += sonic.o
 OBJS-$(CONFIG_SPEEDHQ_DECODER)         += speedhq.o mpeg12.o mpeg12data.o simple_idct.o
 OBJS-$(CONFIG_SPEEDHQ_ENCODER)         += speedhq.o mpeg12data.o mpeg12enc.o speedhqenc.o
+OBJS-$(CONFIG_SPEEX_DECODER)           += speexdec.o
 OBJS-$(CONFIG_SP5X_DECODER)            += sp5xdec.o
 OBJS-$(CONFIG_SRGC_DECODER)            += mscc.o
 OBJS-$(CONFIG_SRT_DECODER)             += srtdec.o ass.o htmlsubtitles.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index c42aba140d..fc6bf7cc25 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -307,6 +307,7 @@ extern const AVCodec ff_snow_decoder;
 extern const AVCodec ff_sp5x_decoder;
 extern const AVCodec ff_speedhq_decoder;
 extern const AVCodec ff_speedhq_encoder;
+extern const AVCodec ff_speex_decoder;
 extern const AVCodec ff_srgc_decoder;
 extern const AVCodec ff_sunrast_encoder;
 extern const AVCodec ff_sunrast_decoder;
diff --git a/libavcodec/speexdata.h b/libavcodec/speexdata.h
new file mode 100644
index 0000000000..0fb3364424
--- /dev/null
+++ b/libavcodec/speexdata.h
@@ -0,0 +1,780 @@
+/*
+ * Copyright 2002-2008 	Xiph.org Foundation
+ * Copyright 2002-2008 	Jean-Marc Valin
+ * Copyright 2005-2007	Analog Devices Inc.
+ * Copyright 2005-2008	Commonwealth Scientific and Industrial Research Organisation (CSIRO)
+ * Copyright 1993, 2002, 2006 David Rowe
+ * Copyright 2003 		EpicGames
+ * Copyright 1992-1994	Jutta Degener, Carsten Bormann
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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 file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_SPEEXDATA_H
+#define AVCODEC_SPEEXDATA_H
+
+#include "libavutil/common.h"
+
+static const int8_t 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
+};
+
+static const int8_t 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
+};
+
+static const int8_t 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
+};
+
+static const int8_t 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
+};
+
+static const int8_t 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
+};
+
+static const int8_t 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
+};
+
+static const int8_t 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
+};
+
+static const int8_t 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
+};
+
+static const int8_t 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
+};
+
+static const int8_t 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
+};
+
+static const int8_t 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
+};
+
+static const int8_t 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
+};
+
+static const int8_t 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
+};
+
+static const int8_t 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
+};
+
+static const int8_t 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
+};
+
+static const int8_t 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,
+};
+
+static const int8_t 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,
+};
+
+static 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}
+};
+
+static 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 */
+};
+
+static 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 */
+};
+
+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
+};
+
+static const float 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 uint16_t wb_skip_table[8] = { 0, 36, 112, 192, 352, 0, 0, 0 };
+static const float e_ratio_quant[4] = {.25f, .315f, .397f, .5f};
+static const float e_ratio_quant_bounds[3] = {0.2825f, 0.356f, 0.4485f};
+static const float attenuation[10] = { 1.f, 0.961f, 0.852f, 0.698f, 0.527f,
+                                       0.368f, 0.237f, 0.141f, 0.077f, 0.039f };
+static const float exc_gain_quant_scal3_bound[7] = {
+    0.112338f, 0.236980f, 0.369316f, 0.492054f,
+    0.637471f, 0.828874f, 1.132784f
+};
+static const float exc_gain_quant_scal3[8] = { 0.061130f, 0.163546f, 0.310413f,
+    0.428220f, 0.555887f, 0.719055f,
+    0.938694f, 1.326874f };
+static const float exc_gain_quant_scal1_bound[1] = { 0.87798f };
+static const float exc_gain_quant_scal1[2] = { 0.70469f, 1.05127f };
+
+#endif /* AVCODEC_SPEEXDATA_H */
diff --git a/libavcodec/speexdec.c b/libavcodec/speexdec.c
new file mode 100644
index 0000000000..fb6d72226e
--- /dev/null
+++ b/libavcodec/speexdec.c
@@ -0,0 +1,1584 @@
+/*
+ * Copyright 2002-2008 	Xiph.org Foundation
+ * Copyright 2002-2008 	Jean-Marc Valin
+ * Copyright 2005-2007	Analog Devices Inc.
+ * Copyright 2005-2008	Commonwealth Scientific and Industrial Research Organisation (CSIRO)
+ * Copyright 1993, 2002, 2006 David Rowe
+ * Copyright 2003 		EpicGames
+ * Copyright 1992-1994	Jutta Degener, Carsten Bormann
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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 file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/avassert.h"
+#include "avcodec.h"
+#include "bytestream.h"
+#include "get_bits.h"
+#include "internal.h"
+#include "speexdata.h"
+
+#define SPEEX_NB_MODES 3
+#define SPEEX_INBAND_STEREO 9
+
+#define QMF_ORDER 64
+#define NB_ORDER 10
+#define NB_FRAME_SIZE 160
+#define NB_SUBMODES 9
+#define NB_SUBMODE_BITS 4
+#define SB_SUBMODE_BITS 3
+
+#define NB_SUBFRAME_SIZE 40
+#define NB_NB_SUBFRAMES 4
+#define NB_PITCH_START 17
+#define NB_PITCH_END 144
+
+#define NB_DEC_BUFFER (NB_FRAME_SIZE + 2 * NB_PITCH_END + NB_SUBFRAME_SIZE + 12)
+
+#define SPEEX_MEMSET(dst, c, n) (memset((dst), (c), (n) * sizeof(*(dst))))
+#define SPEEX_COPY(dst, src, n) (memcpy((dst), (src), (n) * sizeof(*(dst))))
+
+#define LSP_LINEAR(i) (.25f * (i) + .25f)
+#define LSP_LINEAR_HIGH(i) (.3125f * (i) + .75f)
+#define LSP_DIV_256(x) (0.00390625f * (x))
+#define LSP_DIV_512(x) (0.001953125f * (x))
+#define LSP_DIV_1024(x) (0.0009765625f * (x))
+
+typedef struct LtpParams {
+    const int8_t *gain_cdbk;
+    int gain_bits;
+    int pitch_bits;
+} LtpParam;
+
+static const LtpParam ltp_params_vlbr = { gain_cdbk_lbr, 5, 0 };
+static const LtpParam ltp_params_lbr  = { gain_cdbk_lbr, 5, 7 };
+static const LtpParam ltp_params_med  = { gain_cdbk_lbr, 5, 7 };
+static const LtpParam ltp_params_nb   = { gain_cdbk_nb,  7, 7 };
+
+typedef struct SplitCodebookParams {
+    int subvect_size;
+    int nb_subvect;
+    const signed char *shape_cb;
+    int shape_bits;
+    int have_sign;
+} SplitCodebookParams;
+
+static const SplitCodebookParams split_cb_nb_ulbr = { 20, 2, exc_20_32_table, 5, 0 };
+static const SplitCodebookParams split_cb_nb_vlbr = { 10, 4, exc_10_16_table, 4, 0 };
+static const SplitCodebookParams split_cb_nb_lbr  = { 10, 4, exc_10_32_table, 5, 0 };
+static const SplitCodebookParams split_cb_nb_med  = {  8, 5, exc_8_128_table, 7, 0 };
+static const SplitCodebookParams split_cb_nb      = {  5, 8, exc_5_64_table,  6, 0 };
+static const SplitCodebookParams split_cb_sb      = {  5, 8, exc_5_256_table, 8, 0 };
+static const SplitCodebookParams split_cb_high    = {  8, 5, hexc_table,      7, 1 };
+static const SplitCodebookParams split_cb_high_lbr= { 10, 4, hexc_10_32_table,5, 0 };
+
+/** Quantizes LSPs */
+typedef void (*lsp_quant_func)(float *, float *, int, GetBitContext *);
+
+/** Decodes quantized LSPs */
+typedef void (*lsp_unquant_func)(float *, int, GetBitContext *);
+
+/** Long-term predictor quantization */
+typedef int (*ltp_quant_func)(float *, float *, float *,
+    float *, float *, float *,
+    const void *, int, int, float, int, int,
+    GetBitContext *, char *, float *,
+    float *, int, int, int, float *);
+
+/** Long-term un-quantize */
+typedef void (*ltp_unquant_func)(float *, float *, int, int,
+    float, const void *, int, int *,
+    float *, GetBitContext *, int, int,
+    float, int);
+
+/** Innovation quantization function */
+typedef void (*innovation_quant_func)(float *, float *,
+    float *, float *, const void *,
+    int, int, float *, float *,
+    GetBitContext *, char *, int, int);
+
+/** Innovation unquantization function */
+typedef void (*innovation_unquant_func)(float *, const void *, int,
+    GetBitContext *, int32_t *);
+
+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_unquant_func lsp_unquant; /**< LSP unquantization function */
+
+    ltp_unquant_func ltp_unquant; /**< Long-term predictor (pitch) un-quantizer */
+    const void *LtpParam; /**< Pitch parameters (options) */
+
+    innovation_unquant_func innovation_unquant; /**< Innovation un-quantization */
+    const void *innovation_params; /**< Innovation quantization parameters*/
+
+    float comb_gain; /**< Gain of enhancer comb filter */
+} SpeexSubmode;
+
+typedef struct SpeexBMode {
+    int frame_size; /**< Size of frames used for decoding */
+    int subframe_size; /**< Size of sub-frames used for decoding */
+    int lpc_size; /**< Order of LPC filter */
+    float folding_gain; /**< Folding gain */
+    const SpeexSubmode *submodes[NB_SUBMODES]; /**< Sub-mode data for the mode */
+    int default_submode; /**< Default sub-mode to use when decoding */
+} SpeexBMode;
+
+typedef struct DecoderState {
+    const SpeexBMode *mode;
+    int modeID; /** ID of the decoder mode */
+    int first; /** Is first frame  */
+    int full_frame_size; /**< Length of full-band frames */
+    int is_wideband; /**< If wideband is present */
+    int count_lost; /**< Was the last frame lost? */
+    int frame_size; /**< Length of high-band frames */
+    int subframe_size; /**< Length of high-band sub-frames */
+    int nb_subframes; /**< Number of high-band sub-frames */
+    int lpc_size; /**< Order of high-band LPC analysis */
+    float last_ol_gain; /**< Open-loop gain for previous frame */
+    float *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 */
+    float last_pitch_gain; /**< Pitch gain of last correctly decoded frame */
+    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 */
+
+    /* Vocoder data */
+    float voc_m1;
+    float voc_m2;
+    float voc_mean;
+    int voc_offset;
+
+    int dtx_enabled;
+    int highpass_enabled; /**< Is the input filter enabled */
+
+    float *exc; /**< Start of excitation frame */
+    float mem_hp[2]; /**< High-pass filter memory */
+    float exc_buf[NB_DEC_BUFFER]; /**< Excitation buffer */
+    float old_qlsp[NB_ORDER]; /**< Quantized LSPs for previous frame */
+    float interp_qlpc[NB_ORDER]; /**< Interpolated quantized LPCs */
+    float mem_sp[NB_ORDER]; /**< Filter memory for synthesis signal */
+    float g0_mem[QMF_ORDER];
+    float g1_mem[QMF_ORDER];
+    float pi_gain[NB_NB_SUBFRAMES]; /**< Gain of LPC filter at theta=pi (fe/2) */
+    float exc_rms[NB_NB_SUBFRAMES]; /**< RMS of excitation per subframe */
+} DecoderState;
+
+typedef struct SpeexMode {
+    const void *mode; /** Pointer to the low-level mode data */
+    int modeID; /** ID of the mode */
+    int (*decode)(AVCodecContext *avctx, DecoderState *dec, GetBitContext *gb, float *out);
+} SpeexMode;
+
+/* Default handler for user callbacks: skip it */
+static int speex_default_user_handler(GetBitContext *gb, void *state, void *data)
+{
+    const int req_size = get_bits(gb, 4);
+    skip_bits_long(gb, 5 + 8 * req_size);
+    return 0;
+}
+
+typedef struct StereoState {
+    float balance; /**< Left/right balance info */
+    float e_ratio; /**< Ratio of energies: E(left+right)/[E(left)+E(right)]  */
+    float smooth_left; /**< Smoothed left channel gain */
+    float smooth_right; /**< Smoothed right channel gain */
+} StereoState;
+
+typedef struct SpeexContext {
+    AVClass *class;
+    GetBitContext gb;
+
+    int32_t version_id; /**< Version for Speex (for checking compatibility) */
+    int32_t rate; /**< Sampling rate used */
+    int32_t mode; /**< Mode used (0 for narrowband, 1 for wideband) */
+    int32_t bitstream_version; /**< Version ID of the bit-stream */
+    int32_t nb_channels; /**< Number of channels decoded */
+    int32_t bitrate; /**< Bit-rate used */
+    int32_t frame_size; /**< Size of frames */
+    int32_t vbr; /**< 1 for a VBR decoding, 0 otherwise */
+    int32_t frames_per_packet; /**< Number of frames stored per Ogg packet */
+    int32_t extra_headers; /**< Number of additional headers after the comments */
+
+    int pkt_size;
+
+    StereoState stereo;
+    DecoderState st[SPEEX_NB_MODES];
+} SpeexContext;
+
+static void lsp_unquant_lbr(float *lsp, int order, GetBitContext *gb)
+{
+    int id;
+
+    for (int i = 0; i < order; i++)
+        lsp[i] = LSP_LINEAR(i);
+
+    id = get_bits(gb, 6);
+    for (int i = 0; i < 10; i++)
+        lsp[i] += LSP_DIV_256(cdbk_nb[id * 10 + i]);
+
+    id = get_bits(gb, 6);
+    for (int i = 0; i < 5; i++)
+        lsp[i] += LSP_DIV_512(cdbk_nb_low1[id * 5 + i]);
+
+    id = get_bits(gb, 6);
+    for (int i = 0; i < 5; i++)
+        lsp[i + 5] += LSP_DIV_512(cdbk_nb_high1[id * 5 + i]);
+}
+
+static void forced_pitch_unquant(float *exc, float *exc_out, int start, int end,
+                                 float pitch_coef, const void *par, int nsf,
+                                 int *pitch_val, float *gain_val, GetBitContext *gb, int count_lost,
+                                 int subframe_offset, float last_pitch_gain, int cdbk_offset)
+{
+    av_assert0(!isnan(pitch_coef));
+    pitch_coef = fminf(pitch_coef, .99f);
+    for (int i = 0; i < nsf; i++) {
+        exc_out[i] = exc[i - start] * pitch_coef;
+        exc[i] = exc_out[i];
+    }
+    pitch_val[0] = start;
+    gain_val[0] = gain_val[2] = 0.f;
+    gain_val[1] = pitch_coef;
+}
+
+static inline float speex_rand(float std, int32_t *seed)
+{
+    const uint32_t jflone = 0x3f800000;
+    const uint32_t jflmsk = 0x007fffff;
+    float fran;
+    uint32_t ran;
+    seed[0] = 1664525 * seed[0] + 1013904223;
+    ran = jflone | (jflmsk & seed[0]);
+    fran = av_int2float(ran);
+    fran -= 1.5f;
+    fran *= std;
+    return fran;
+}
+
+static void noise_codebook_unquant(float *exc, const void *par, int nsf,
+                                   GetBitContext *gb, int32_t *seed)
+{
+    for (int i = 0; i < nsf; i++)
+        exc[i] = speex_rand(1.f, seed);
+}
+
+static void split_cb_shape_sign_unquant(float *exc, const void *par, int nsf,
+                                        GetBitContext *gb, int32_t *seed)
+{
+    int subvect_size, nb_subvect, have_sign, shape_bits;
+    const SplitCodebookParams *params;
+    const signed char *shape_cb;
+    int signs[10], ind[10];
+
+    params = par;
+    subvect_size = params->subvect_size;
+    nb_subvect = params->nb_subvect;
+
+    shape_cb = params->shape_cb;
+    have_sign = params->have_sign;
+    shape_bits = params->shape_bits;
+
+    /* Decode codewords and gains */
+    for (int i = 0; i < nb_subvect; i++) {
+        signs[i] = have_sign ? get_bits1(gb) : 0;
+        ind[i] = get_bitsz(gb, shape_bits);
+    }
+    /* Compute decoded excitation */
+    for (int i = 0; i < nb_subvect; i++) {
+        const float s = signs[i] ? -1.f : 1.f;
+
+        for (int j = 0; j < subvect_size; j++)
+            exc[subvect_size * i + j] += s * 0.03125f * shape_cb[ind[i] * subvect_size + j];
+    }
+}
+
+#define SUBMODE(x) st->submodes[st->submodeID]->x
+
+#define gain_3tap_to_1tap(g) (FFABS(g[1]) + (g[0] > 0.f ? g[0] : -.5f * g[0]) + (g[2] > 0.f ? g[2] : -.5f * g[2]))
+
+static void
+pitch_unquant_3tap(float *exc, float *exc_out, int start, int end, float pitch_coef,
+                   const void *par, int nsf, int *pitch_val, float *gain_val, GetBitContext *gb,
+                   int count_lost, int subframe_offset, float last_pitch_gain, int cdbk_offset)
+{
+    int pitch, gain_index, gain_cdbk_size;
+    const int8_t *gain_cdbk;
+    const LtpParam *params;
+    float gain[3];
+
+    params = (const LtpParam *)par;
+    gain_cdbk_size = 1 << params->gain_bits;
+    gain_cdbk = params->gain_cdbk + 4 * gain_cdbk_size * cdbk_offset;
+
+    pitch = get_bitsz(gb, params->pitch_bits);
+    pitch += start;
+    gain_index = get_bitsz(gb, params->gain_bits);
+    gain[0] = 0.015625f * gain_cdbk[gain_index * 4] + .5f;
+    gain[1] = 0.015625f * gain_cdbk[gain_index * 4 + 1] + .5f;
+    gain[2] = 0.015625f * gain_cdbk[gain_index * 4 + 2] + .5f;
+
+    if (count_lost && pitch > subframe_offset) {
+        float tmp = count_lost < 4 ? last_pitch_gain : 0.5f * last_pitch_gain;
+        float gain_sum;
+
+        tmp = fminf(tmp, .95f);
+        gain_sum = gain_3tap_to_1tap(gain);
+
+        if (gain_sum > tmp && gain_sum > 0.f) {
+            float fact = tmp / gain_sum;
+            for (int i = 0; i < 3; i++)
+                gain[i] *= fact;
+        }
+    }
+
+    pitch_val[0] = pitch;
+    gain_val[0] = gain[0];
+    gain_val[1] = gain[1];
+    gain_val[2] = gain[2];
+    SPEEX_MEMSET(exc_out, 0, nsf);
+
+    for (int i = 0; i < 3; i++) {
+        int tmp1, tmp3;
+        int pp = pitch + 1 - i;
+        tmp1 = nsf;
+        if (tmp1 > pp)
+            tmp1 = pp;
+        for (int j = 0; j < tmp1; j++)
+            exc_out[j] += gain[2 - i] * exc[j - pp];
+        tmp3 = nsf;
+        if (tmp3 > pp + pitch)
+            tmp3 = pp + pitch;
+        for (int j = tmp1; j < tmp3; j++)
+            exc_out[j] += gain[2 - i] * exc[j - pp - pitch];
+    }
+}
+
+static void lsp_unquant_nb(float *lsp, int order, GetBitContext *gb)
+{
+    int id;
+
+    for (int i = 0; i < order; i++)
+        lsp[i] = LSP_LINEAR(i);
+
+    id = get_bits(gb, 6);
+    for (int i = 0; i < 10; i++)
+        lsp[i] += LSP_DIV_256(cdbk_nb[id * 10 + i]);
+
+    id = get_bits(gb, 6);
+    for (int i = 0; i < 5; i++)
+        lsp[i] += LSP_DIV_512(cdbk_nb_low1[id * 5 + i]);
+
+    id = get_bits(gb, 6);
+    for (int i = 0; i < 5; i++)
+        lsp[i] += LSP_DIV_1024(cdbk_nb_low2[id * 5 + i]);
+
+    id = get_bits(gb, 6);
+    for (int i = 0; i < 5; i++)
+        lsp[i + 5] += LSP_DIV_512(cdbk_nb_high1[id * 5 + i]);
+
+    id = get_bits(gb, 6);
+    for (int i = 0; i < 5; i++)
+        lsp[i + 5] += LSP_DIV_1024(cdbk_nb_high2[id * 5 + i]);
+}
+
+static void lsp_unquant_high(float *lsp, int order, GetBitContext *gb)
+{
+    int id;
+
+    for (int i = 0; i < order; i++)
+        lsp[i] = LSP_LINEAR_HIGH(i);
+
+    id = get_bits(gb, 6);
+    for (int i = 0; i < order; i++)
+        lsp[i] += LSP_DIV_256(high_lsp_cdbk[id * order + i]);
+
+    id = get_bits(gb, 6);
+    for (int i = 0; i < order; i++)
+        lsp[i] += LSP_DIV_512(high_lsp_cdbk2[id * order + i]);
+}
+
+/* 2150 bps "vocoder-like" mode for comfort noise */
+static const SpeexSubmode nb_submode1 = {
+    0, 1, 0, 0, lsp_unquant_lbr, forced_pitch_unquant, NULL,
+    noise_codebook_unquant, NULL, -1.f
+};
+
+/* 5.95 kbps very low bit-rate mode */
+static const SpeexSubmode nb_submode2 = {
+    0, 0, 0, 0, lsp_unquant_lbr, pitch_unquant_3tap, &ltp_params_vlbr,
+    split_cb_shape_sign_unquant, &split_cb_nb_vlbr, .6f
+};
+
+/* 8 kbps low bit-rate mode */
+static const SpeexSubmode nb_submode3 = {
+    -1, 0, 1, 0, lsp_unquant_lbr, pitch_unquant_3tap, &ltp_params_lbr,
+    split_cb_shape_sign_unquant, &split_cb_nb_lbr, .55f
+};
+
+/* 11 kbps medium bit-rate mode */
+static const SpeexSubmode nb_submode4 = {
+    -1, 0, 1, 0, lsp_unquant_lbr, pitch_unquant_3tap, &ltp_params_med,
+    split_cb_shape_sign_unquant, &split_cb_nb_med, .45f
+};
+
+/* 15 kbps high bit-rate mode */
+static const SpeexSubmode nb_submode5 = {
+    -1, 0, 3, 0, lsp_unquant_nb, pitch_unquant_3tap, &ltp_params_nb,
+    split_cb_shape_sign_unquant, &split_cb_nb, .25f
+};
+
+/* 18.2 high bit-rate mode */
+static const SpeexSubmode nb_submode6 = {
+    -1, 0, 3, 0, lsp_unquant_nb, pitch_unquant_3tap, &ltp_params_nb,
+    split_cb_shape_sign_unquant, &split_cb_sb, .15f
+};
+
+/* 24.6 kbps high bit-rate mode */
+static const SpeexSubmode nb_submode7 = {
+    -1, 0, 3, 1, lsp_unquant_nb, pitch_unquant_3tap, &ltp_params_nb,
+    split_cb_shape_sign_unquant, &split_cb_nb, 0.05f
+};
+
+/* 3.95 kbps very low bit-rate mode */
+static const SpeexSubmode nb_submode8 = {
+    0, 1, 0, 0, lsp_unquant_lbr, forced_pitch_unquant, NULL,
+    split_cb_shape_sign_unquant, &split_cb_nb_ulbr, .5f
+};
+
+static const SpeexSubmode wb_submode1 = {
+    0, 0, 1, 0, lsp_unquant_high, NULL, NULL,
+    NULL, NULL, -1.f
+};
+
+static const SpeexSubmode wb_submode2 = {
+    0, 0, 1, 0, lsp_unquant_high, NULL, NULL,
+    split_cb_shape_sign_unquant, &split_cb_high_lbr, -1.f
+};
+
+static const SpeexSubmode wb_submode3 = {
+    0, 0, 1, 0, lsp_unquant_high, NULL, NULL,
+    split_cb_shape_sign_unquant, &split_cb_high, -1.f
+};
+
+static const SpeexSubmode wb_submode4 = {
+    0, 0, 1, 1, lsp_unquant_high, NULL, NULL,
+    split_cb_shape_sign_unquant, &split_cb_high, -1.f
+};
+
+static const SpeexBMode narrowband_mode =
+{
+    .frame_size = NB_FRAME_SIZE,
+    .subframe_size = NB_SUBFRAME_SIZE,
+    .lpc_size = NB_ORDER,
+    .submodes = {
+        NULL, &nb_submode1, &nb_submode2, &nb_submode3, &nb_submode4,
+        &nb_submode5, &nb_submode6, &nb_submode7, &nb_submode8
+    },
+    .default_submode = 5,
+};
+
+static const SpeexBMode wideband_mode = {
+    .frame_size = NB_FRAME_SIZE,
+    .subframe_size = NB_SUBFRAME_SIZE,
+    .lpc_size = 8,
+    .folding_gain = 0.9f,
+    .submodes = {
+        NULL, &wb_submode1, &wb_submode2, &wb_submode3, &wb_submode4
+    },
+    .default_submode = 3,
+};
+
+static const SpeexBMode ultrawideband_mode = {
+    .frame_size = 320,
+    .subframe_size = 80,
+    .lpc_size = 8,
+    .folding_gain = 0.7f,
+    .submodes = {
+        NULL, &wb_submode1
+    },
+    .default_submode = 1,
+};
+
+static float compute_rms(const float *x, int len)
+{
+    float sum = 0.f;
+
+    for (int i = 0; i < len; i++)
+        sum += x[i] * x[i];
+
+    av_assert0(len > 0);
+    return sqrtf(.1f + sum / len);
+}
+
+static void bw_lpc(float gamma, const float *lpc_in,
+                   float *lpc_out, int order)
+{
+    float tmp = gamma;
+
+    for (int i = 0; i < order; i++) {
+        lpc_out[i] = tmp * lpc_in[i];
+        tmp *= gamma;
+    }
+}
+
+static void iir_mem(const float *x, const float *den,
+    float *y, int N, int ord, float *mem)
+{
+    for (int i = 0; i < N; i++) {
+        float yi = x[i] + mem[0];
+        float nyi = -yi;
+        for (int j = 0; j < ord - 1; j++)
+            mem[j] = mem[j + 1] + den[j] * nyi;
+        mem[ord - 1] = den[ord - 1] * nyi;
+        y[i] = yi;
+    }
+}
+
+static void highpass(const float *x, float *y, int len, float *mem, int wide)
+{
+    static const float Pcoef[2][3] = {{ 1.00000f, -1.92683f, 0.93071f }, { 1.00000f, -1.97226f, 0.97332f } };
+    static const float Zcoef[2][3] = {{ 0.96446f, -1.92879f, 0.96446f }, { 0.98645f, -1.97277f, 0.98645f } };
+    const float *den, *num;
+
+    den = Pcoef[wide];
+    num = Zcoef[wide];
+    for (int i = 0; i < len; i++) {
+        float yi = num[0] * x[i] + mem[0];
+        mem[0] = mem[1] + num[1] * x[i] + -den[1] * yi;
+        mem[1] = num[2] * x[i] + -den[2] * yi;
+        y[i] = yi;
+    }
+}
+
+#define median3(a, b, c)                                     \
+    ((a) < (b) ? ((b) < (c) ? (b) : ((a) < (c) ? (c) : (a))) \
+               : ((c) < (b) ? (b) : ((c) < (a) ? (c) : (a))))
+
+static int speex_std_stereo(GetBitContext *gb, void *state, void *data)
+{
+    StereoState *stereo = data;
+    float sign = get_bits1(gb) ? -1.f : 1.f;
+
+    stereo->balance = exp(sign * .25f * get_bits(gb, 5));
+    stereo->e_ratio = e_ratio_quant[get_bits(gb, 2)];
+
+    return 0;
+}
+
+static int speex_inband_handler(GetBitContext *gb, void *state, StereoState *stereo)
+{
+    int id = get_bits(gb, 4);
+
+    if (id == SPEEX_INBAND_STEREO) {
+        return speex_std_stereo(gb, state, stereo);
+    } else {
+        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;
+        skip_bits_long(gb, adv);
+    }
+    return 0;
+}
+
+static void sanitize_values(float *vec, float min_val, float max_val, int len)
+{
+    for (int i = 0; i < len; i++) {
+        if (!isnormal(vec[i]) || fabsf(vec[i]) < 1e-8f)
+            vec[i] = 0.f;
+        else
+            vec[i] = av_clipf(vec[i], min_val, max_val);
+    }
+}
+
+static void signal_mul(const float *x, float *y, float scale, int len)
+{
+    for (int i = 0; i < len; i++)
+        y[i] = scale * x[i];
+}
+
+static float inner_prod(const float *x, const float *y, int len)
+{
+    float sum = 0.f;
+
+    for (int i = 0; i < len; i += 8) {
+        float part = 0.f;
+        part += x[i + 0] * y[i + 0];
+        part += x[i + 1] * y[i + 1];
+        part += x[i + 2] * y[i + 2];
+        part += x[i + 3] * y[i + 3];
+        part += x[i + 4] * y[i + 4];
+        part += x[i + 5] * y[i + 5];
+        part += x[i + 6] * y[i + 6];
+        part += x[i + 7] * y[i + 7];
+        sum += part;
+    }
+
+    return sum;
+}
+
+static int interp_pitch(const float *exc, float *interp, int pitch, int len)
+{
+    float corr[4][7], maxcorr;
+    int maxi, maxj;
+
+    for (int i = 0; i < 7; i++)
+        corr[0][i] = inner_prod(exc, exc - pitch - 3 + i, len);
+    for (int i = 0; i < 3; i++) {
+        for (int j = 0; j < 7; j++) {
+            int i1, i2;
+            float tmp = 0.f;
+
+            i1 = 3 - j;
+            if (i1 < 0)
+                i1 = 0;
+            i2 = 10 - j;
+            if (i2 > 7)
+                i2 = 7;
+            for (int k = i1; k < i2; k++)
+                tmp += shift_filt[i][k] * corr[0][j + k - 3];
+            corr[i + 1][j] = tmp;
+        }
+    }
+    maxi = maxj = 0;
+    maxcorr = corr[0][0];
+    for (int i = 0; i < 4; i++) {
+        for (int j = 0; j < 7; j++) {
+            if (corr[i][j] > maxcorr) {
+                maxcorr = corr[i][j];
+                maxi = i;
+                maxj = j;
+            }
+        }
+    }
+    for (int i = 0; i < len; i++) {
+        float tmp = 0.f;
+        if (maxi > 0.f) {
+            for (int k = 0; k < 7; k++)
+                tmp += exc[i - (pitch - maxj + 3) + k - 3] * shift_filt[maxi - 1][k];
+        } else {
+            tmp = exc[i - (pitch - maxj + 3)];
+        }
+        interp[i] = tmp;
+    }
+    return pitch - maxj + 3;
+}
+
+static void multicomb(const float *exc, float *new_exc, float *ak, int p, int nsf,
+                      int pitch, int max_pitch, float comb_gain)
+{
+    float old_ener, new_ener;
+    float iexc0_mag, iexc1_mag, exc_mag;
+    float iexc[4 * NB_SUBFRAME_SIZE];
+    float corr0, corr1, gain0, gain1;
+    float pgain1, pgain2;
+    float c1, c2, g1, g2;
+    float ngain, gg1, gg2;
+    int corr_pitch = pitch;
+
+    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);
+
+    iexc0_mag = sqrtf(1000.f + inner_prod(iexc, iexc, nsf));
+    iexc1_mag = sqrtf(1000.f + inner_prod(iexc + nsf, iexc + nsf, nsf));
+    exc_mag = sqrtf(1.f + inner_prod(exc, exc, nsf));
+    corr0 = inner_prod(iexc, exc, nsf);
+    corr1 = inner_prod(iexc + nsf, exc, nsf);
+    if (corr0 > iexc0_mag * exc_mag)
+        pgain1 = 1.f;
+    else
+        pgain1 = (corr0 / exc_mag) / iexc0_mag;
+    if (corr1 > iexc1_mag * exc_mag)
+        pgain2 = 1.f;
+    else
+        pgain2 = (corr1 / exc_mag) / iexc1_mag;
+    gg1 = exc_mag / iexc0_mag;
+    gg2 = exc_mag / iexc1_mag;
+    if (comb_gain > 0.f) {
+        c1 = .4f * comb_gain + .07f;
+        c2 = .5f + 1.72f * (c1 - .07f);
+    } else {
+        c1 = c2 = 0.f;
+    }
+    g1 = 1.f - c2 * pgain1 * pgain1;
+    g2 = 1.f - c2 * pgain2 * pgain2;
+    g1 = fmaxf(g1, c1);
+    g2 = fmaxf(g2, c1);
+    g1 = c1 / g1;
+    g2 = c1 / g2;
+
+    if (corr_pitch > max_pitch) {
+        gain0 = .7f * g1 * gg1;
+        gain1 = .3f * g2 * gg2;
+    } else {
+        gain0 = .6f * g1 * gg1;
+        gain1 = .6f * g2 * gg2;
+    }
+    for (int i = 0; i < nsf; i++)
+        new_exc[i] = exc[i] + (gain0 * iexc[i]) + (gain1 * iexc[i + nsf]);
+    new_ener = compute_rms(new_exc, nsf);
+    old_ener = compute_rms(exc, nsf);
+
+    old_ener = fmaxf(old_ener, 1.f);
+    new_ener = fmaxf(new_ener, 1.f);
+    old_ener = fminf(old_ener, new_ener);
+    ngain = old_ener / new_ener;
+
+    for (int i = 0; i < nsf; i++)
+        new_exc[i] *= ngain;
+}
+
+static void lsp_interpolate(const float *old_lsp, const float *new_lsp,
+                            float *lsp, int len, int subframe,
+                            int nb_subframes, float margin)
+{
+    const float tmp = (1.f + subframe) / nb_subframes;
+
+    for (int i = 0; i < len; i++) {
+        lsp[i] = (1.f - tmp) * old_lsp[i] + tmp * new_lsp[i];
+        lsp[i] = av_clipf(lsp[i], margin, M_PI - margin);
+    }
+    for (int i = 1; i < len - 1; i++) {
+        lsp[i] = fmaxf(lsp[i], lsp[i - 1] + margin);
+        if (lsp[i] > lsp[i + 1] - margin)
+            lsp[i] = .5f * (lsp[i] + lsp[i + 1] - margin);
+    }
+}
+
+static void lsp_to_lpc(const float *freq, float *ak, int lpcrdr)
+{
+    float xout1, xout2, xin1, xin2;
+    float *pw, *n0;
+    float Wp[4 * NB_ORDER + 2] = { 0 };
+    float x_freq[NB_ORDER];
+    const int m = lpcrdr >> 1;
+
+    pw = Wp;
+
+    xin1 = xin2 = 1.f;
+
+    for (int i = 0; i < lpcrdr; i++)
+        x_freq[i] = -cosf(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 (int j = 0; j <= lpcrdr; j++) {
+        int i2 = 0;
+        for (int i = 0; i < m; i++, i2 += 2) {
+            n0 = pw + (i * 4);
+            xout1 = xin1 + 2.f * x_freq[i2    ] * n0[0] + n0[1];
+            xout2 = xin2 + 2.f * x_freq[i2 + 1] * n0[2] + n0[3];
+            n0[1] = n0[0];
+            n0[3] = n0[2];
+            n0[0] = xin1;
+            n0[2] = xin2;
+            xin1 = xout1;
+            xin2 = xout2;
+        }
+        xout1 = xin1 + n0[4];
+        xout2 = xin2 - n0[5];
+        if (j > 0)
+            ak[j - 1] = (xout1 + xout2) * 0.5f;
+        n0[4] = xin1;
+        n0[5] = xin2;
+
+        xin1 = 0.f;
+        xin2 = 0.f;
+    }
+}
+
+static int nb_decode(AVCodecContext *avctx, DecoderState *st,
+                     GetBitContext *gb, float *out)
+{
+    float ol_gain = 0, ol_pitch_coef = 0, best_pitch_gain = 0, pitch_average = 0;
+    int m, pitch, wideband, ol_pitch = 0, best_pitch = 40;
+    SpeexContext *s = avctx->priv_data;
+    float innov[NB_SUBFRAME_SIZE];
+    float exc32[NB_SUBFRAME_SIZE];
+    float interp_qlsp[NB_ORDER];
+    float qlsp[NB_ORDER];
+    float ak[NB_ORDER];
+    float pitch_gain[3] = { 0 };
+
+    st->exc = st->exc_buf + 2 * NB_PITCH_END + NB_SUBFRAME_SIZE + 6;
+
+    if (st->encode_submode) {
+        do { /* Search for next narrowband block (handle requests, skip wideband blocks) */
+            if (get_bits_left(gb) < 5)
+                return AVERROR_INVALIDDATA;
+            wideband = get_bits1(gb);
+            if (wideband) /* Skip wideband block (for compatibility) */ {
+                int submode, advance;
+
+                submode = get_bits(gb, SB_SUBMODE_BITS);
+                advance = wb_skip_table[submode];
+                advance -= SB_SUBMODE_BITS + 1;
+                if (advance < 0)
+                    return AVERROR_INVALIDDATA;
+                skip_bits_long(gb, advance);
+
+                if (get_bits_left(gb) < 5)
+                    return AVERROR_INVALIDDATA;
+                wideband = get_bits1(gb);
+                if (wideband) {
+                    submode = get_bits(gb, SB_SUBMODE_BITS);
+                    advance = wb_skip_table[submode];
+                    advance -= SB_SUBMODE_BITS + 1;
+                    if (advance < 0)
+                        return AVERROR_INVALIDDATA;
+                    skip_bits_long(gb, advance);
+                    wideband = get_bits1(gb);
+                    if (wideband) {
+                        av_log(avctx, AV_LOG_ERROR, "more than two wideband layers found\n");
+                        return AVERROR_INVALIDDATA;
+                    }
+                }
+            }
+            if (get_bits_left(gb) < 4)
+                return AVERROR_INVALIDDATA;
+            m = get_bits(gb, 4);
+            if (m == 15) /* We found a terminator */ {
+                return AVERROR_INVALIDDATA;
+            } else if (m == 14) /* Speex in-band request */ {
+                int ret = speex_inband_handler(gb, st, &s->stereo);
+                if (ret)
+                    return ret;
+            } else if (m == 13) /* User in-band request */ {
+                int ret = speex_default_user_handler(gb, st, NULL);
+                if (ret)
+                    return ret;
+            } else if (m > 8) /* Invalid mode */ {
+                return AVERROR_INVALIDDATA;
+            }
+        } while (m > 8);
+
+        st->submodeID = m; /* Get the sub-mode that was used */
+    }
+
+    /* Shift all buffers by one frame */
+    memmove(st->exc_buf, st->exc_buf + NB_FRAME_SIZE, (2 * NB_PITCH_END + NB_SUBFRAME_SIZE + 12) * sizeof(float));
+
+    /* If null mode (no transmission), just set a couple things to zero */
+    if (st->submodes[st->submodeID] == NULL) {
+        float lpc[NB_ORDER];
+        float innov_gain = 0.f;
+
+        bw_lpc(0.93f, st->interp_qlpc, lpc, NB_ORDER);
+        innov_gain = compute_rms(st->exc, NB_FRAME_SIZE);
+        for (int i = 0; i < NB_FRAME_SIZE; i++)
+            st->exc[i] = speex_rand(innov_gain, &st->seed);
+
+        /* Final signal synthesis from excitation */
+        iir_mem(st->exc, lpc, out, NB_FRAME_SIZE, NB_ORDER, st->mem_sp);
+        st->count_lost = 0;
+
+        return 0;
+    }
+
+    /* Unquantize LSPs */
+    SUBMODE(lsp_unquant)(qlsp, NB_ORDER, gb);
+
+    /* Damp memory if a frame was lost and the LSP changed too much */
+    if (st->count_lost) {
+        float fact, lsp_dist = 0;
+
+        for (int i = 0; i < NB_ORDER; i++)
+            lsp_dist = lsp_dist + FFABS(st->old_qlsp[i] - qlsp[i]);
+        fact = .6f * exp(-.2f * lsp_dist);
+        for (int i = 0; i < NB_ORDER; i++)
+            st->mem_sp[i] = fact * st->mem_sp[i];
+    }
+
+    /* Handle first frame and lost-packet case */
+    if (st->first || st->count_lost)
+        memcpy(st->old_qlsp, qlsp, sizeof(st->old_qlsp));
+
+    /* Get open-loop pitch estimation for low bit-rate pitch coding */
+    if (SUBMODE(lbr_pitch) != -1)
+        ol_pitch = NB_PITCH_START + get_bits(gb, 7);
+
+    if (SUBMODE(forced_pitch_gain))
+        ol_pitch_coef = 0.066667f * get_bits(gb, 4);
+
+    /* Get global excitation gain */
+    ol_gain = expf(get_bits(gb, 5) / 3.5f);
+
+    if (st->submodeID == 1)
+        st->dtx_enabled = get_bits(gb, 4) == 15;
+
+    if (st->submodeID > 1)
+        st->dtx_enabled = 0;
+
+    for (int sub = 0; sub < NB_NB_SUBFRAMES; sub++) { /* Loop on subframes */
+        float *exc, *innov_save = NULL, tmp, ener;
+        int pit_min, pit_max, offset, q_energy;
+
+        offset = NB_SUBFRAME_SIZE * sub; /* Offset relative to start of frame */
+        exc = st->exc + offset; /* Excitation */
+        if (st->innov_save) /* Original signal */
+            innov_save = st->innov_save + offset;
+
+        SPEEX_MEMSET(exc, 0, NB_SUBFRAME_SIZE); /* Reset excitation */
+
+        /* Adaptive codebook contribution */
+        av_assert0(SUBMODE(ltp_unquant));
+        /* Handle pitch constraints if any */
+        if (SUBMODE(lbr_pitch) != -1) {
+            int margin = SUBMODE(lbr_pitch);
+
+            if (margin) {
+                pit_min = ol_pitch - margin + 1;
+                pit_min = FFMAX(pit_min, NB_PITCH_START);
+                pit_max = ol_pitch + margin;
+                pit_max = FFMIN(pit_max, NB_PITCH_START);
+            } else {
+                pit_min = pit_max = ol_pitch;
+            }
+        } else {
+            pit_min = NB_PITCH_START;
+            pit_max = NB_PITCH_END;
+        }
+
+        SUBMODE(ltp_unquant)(exc, exc32, pit_min, pit_max, ol_pitch_coef, SUBMODE(LtpParam),
+                             NB_SUBFRAME_SIZE, &pitch, pitch_gain, gb, st->count_lost, offset,
+                             st->last_pitch_gain, 0);
+
+        sanitize_values(exc32, -32000, 32000, NB_SUBFRAME_SIZE);
+
+        tmp = gain_3tap_to_1tap(pitch_gain);
+
+        pitch_average += tmp;
+        if ((tmp > best_pitch_gain &&
+             FFABS(2 * best_pitch - pitch) >= 3 &&
+             FFABS(3 * best_pitch - pitch) >= 4 &&
+             FFABS(4 * best_pitch - pitch) >= 5) ||
+            (tmp > .6f * best_pitch_gain &&
+             (FFABS(best_pitch - 2 * pitch) < 3 ||
+              FFABS(best_pitch - 3 * pitch) < 4 ||
+              FFABS(best_pitch - 4 * pitch) < 5)) ||
+            ((.67f * tmp) > best_pitch_gain &&
+             (FFABS(2 * best_pitch - pitch) < 3 ||
+              FFABS(3 * best_pitch - pitch) < 4 ||
+              FFABS(4 * best_pitch - pitch) < 5))) {
+            best_pitch = pitch;
+            if (tmp > best_pitch_gain)
+                best_pitch_gain = tmp;
+        }
+
+        memset(innov, 0, sizeof(innov));
+
+        /* Decode sub-frame gain correction */
+        if (SUBMODE(have_subframe_gain) == 3) {
+            q_energy = get_bits(gb, 3);
+            ener = exc_gain_quant_scal3[q_energy] * ol_gain;
+        } else if (SUBMODE(have_subframe_gain) == 1) {
+            q_energy = get_bits1(gb);
+            ener = exc_gain_quant_scal1[q_energy] * ol_gain;
+        } else {
+            ener = ol_gain;
+        }
+
+        av_assert0(SUBMODE(innovation_unquant));
+        /* Fixed codebook contribution */
+        SUBMODE(innovation_unquant)(innov, SUBMODE(innovation_params), NB_SUBFRAME_SIZE, gb, &st->seed);
+        /* De-normalize innovation and update excitation */
+
+        signal_mul(innov, innov, ener, NB_SUBFRAME_SIZE);
+
+        /* Decode second codebook (only for some modes) */
+        if (SUBMODE(double_codebook)) {
+            float innov2[NB_SUBFRAME_SIZE] = { 0 };
+
+            SUBMODE(innovation_unquant)(innov2, SUBMODE(innovation_params), NB_SUBFRAME_SIZE, gb, &st->seed);
+            signal_mul(innov2, innov2, 0.454545f * ener, NB_SUBFRAME_SIZE);
+            for (int i = 0; i < NB_SUBFRAME_SIZE; i++)
+                innov[i] += innov2[i];
+        }
+        for (int i = 0; i < NB_SUBFRAME_SIZE; i++)
+            exc[i] = exc32[i] + innov[i];
+        if (innov_save)
+            memcpy(innov_save, innov, sizeof(innov));
+
+        /* Vocoder mode */
+        if (st->submodeID == 1) {
+            float g = ol_pitch_coef;
+
+            g = av_clipf(1.5f * (g - .2f), 0.f, 1.f);
+
+            SPEEX_MEMSET(exc, 0, NB_SUBFRAME_SIZE);
+            while (st->voc_offset < NB_SUBFRAME_SIZE) {
+                if (st->voc_offset >= 0)
+                    exc[st->voc_offset] = sqrtf(2.f * ol_pitch) * (g * ol_gain);
+                st->voc_offset += ol_pitch;
+            }
+            st->voc_offset -= NB_SUBFRAME_SIZE;
+
+            for (int i = 0; i < NB_SUBFRAME_SIZE; i++) {
+                float exci = exc[i];
+                exc[i] = (.7f * exc[i] + .3f * st->voc_m1) + ((1.f - .85f * g) * innov[i]) - .15f * g * st->voc_m2;
+                st->voc_m1 = exci;
+                st->voc_m2 = innov[i];
+                st->voc_mean = .8f * st->voc_mean + .2f * exc[i];
+                exc[i] -= st->voc_mean;
+            }
+        }
+    }
+
+    if (st->lpc_enh_enabled && SUBMODE(comb_gain) > 0 && !st->count_lost) {
+        multicomb(st->exc - NB_SUBFRAME_SIZE, out, st->interp_qlpc, NB_ORDER,
+            2 * NB_SUBFRAME_SIZE, best_pitch, 40, SUBMODE(comb_gain));
+        multicomb(st->exc + NB_SUBFRAME_SIZE, out + 2 * NB_SUBFRAME_SIZE,
+            st->interp_qlpc, NB_ORDER, 2 * NB_SUBFRAME_SIZE, best_pitch, 40,
+            SUBMODE(comb_gain));
+    } else {
+        SPEEX_COPY(out, &st->exc[-NB_SUBFRAME_SIZE], NB_FRAME_SIZE);
+    }
+
+    /* If the last packet was lost, re-scale the excitation to obtain the same
+     * energy as encoded in ol_gain */
+    if (st->count_lost) {
+        float exc_ener, gain;
+
+        exc_ener = compute_rms(st->exc, NB_FRAME_SIZE);
+        av_assert0(exc_ener + 1.f > 0.f);
+        gain = fminf(ol_gain / (exc_ener + 1.f), 2.f);
+        for (int i = 0; i < NB_FRAME_SIZE; i++) {
+            st->exc[i] *= gain;
+            out[i] = st->exc[i - NB_SUBFRAME_SIZE];
+        }
+    }
+
+    for (int sub = 0; sub < NB_NB_SUBFRAMES; sub++) { /* Loop on subframes */
+        const int offset = NB_SUBFRAME_SIZE * sub; /* Offset relative to start of frame */
+        float pi_g = 1.f, *sp = out + offset; /* Original signal */
+
+        lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, NB_ORDER, sub, NB_NB_SUBFRAMES, 0.002f);
+        lsp_to_lpc(interp_qlsp, ak, NB_ORDER); /* Compute interpolated LPCs (unquantized) */
+
+        for (int i = 0; i < NB_ORDER; i += 2) /* Compute analysis filter at w=pi */
+            pi_g += ak[i + 1] - ak[i];
+        st->pi_gain[sub] = pi_g;
+        st->exc_rms[sub] = compute_rms(st->exc + offset, NB_SUBFRAME_SIZE);
+
+        iir_mem(sp, st->interp_qlpc, sp, NB_SUBFRAME_SIZE, NB_ORDER, st->mem_sp);
+
+        memcpy(st->interp_qlpc, ak, sizeof(st->interp_qlpc));
+    }
+
+    if (st->highpass_enabled)
+        highpass(out, out, NB_FRAME_SIZE, st->mem_hp, st->is_wideband);
+
+    /* Store the LSPs for interpolation in the next frame */
+    memcpy(st->old_qlsp, qlsp, sizeof(st->old_qlsp));
+
+    st->count_lost = 0;
+    st->last_pitch = best_pitch;
+    st->last_pitch_gain = .25f * pitch_average;
+    st->last_ol_gain = ol_gain;
+    st->first = 0;
+
+    return 0;
+}
+
+static void qmf_synth(const float *x1, const float *x2, const float *a, float *y, int N, int M, float *mem1, float *mem2)
+{
+    const int M2 = M >> 1, N2 = N >> 1;
+    float xx1[352], xx2[352];
+
+    for (int i = 0; i < N2; i++)
+        xx1[i] = x1[N2-1-i];
+    for (int i = 0; i < M2; i++)
+        xx1[N2+i] = mem1[2*i+1];
+    for (int i = 0; i < N2; i++)
+        xx2[i] = x2[N2-1-i];
+    for (int i = 0; i < M2; i++)
+        xx2[N2+i] = mem2[2*i+1];
+
+    for (int i = 0; i < N2; i += 2) {
+        float y0, y1, y2, y3;
+        float x10, x20;
+
+        y0 = y1 = y2 = y3 = 0.f;
+        x10 = xx1[N2-2-i];
+        x20 = xx2[N2-2-i];
+
+        for (int j = 0; j < M2; j += 2) {
+            float x11, x21;
+            float a0, a1;
+
+            a0 = a[2*j];
+            a1 = a[2*j+1];
+            x11 = xx1[N2-1+j-i];
+            x21 = xx2[N2-1+j-i];
+
+            y0 += a0 * (x11-x21);
+            y1 += a1 * (x11+x21);
+            y2 += a0 * (x10-x20);
+            y3 += a1 * (x10+x20);
+            a0 = a[2*j+2];
+            a1 = a[2*j+3];
+            x10 = xx1[N2+j-i];
+            x20 = xx2[N2+j-i];
+
+            y0 += a0 * (x10-x20);
+            y1 += a1 * (x10+x20);
+            y2 += a0 * (x11-x21);
+            y3 += a1 * (x11+x21);
+        }
+        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;
+    }
+
+    for (int i = 0; i < M2; i++)
+        mem1[2*i+1] = xx1[i];
+    for (int i = 0; i < M2; i++)
+        mem2[2*i+1] = xx2[i];
+}
+
+static int sb_decode(AVCodecContext *, DecoderState *, GetBitContext *, float *);
+
+static const SpeexMode narrowband = {
+    .mode = &narrowband_mode,
+    .modeID = 0,
+    .decode = nb_decode,
+};
+
+static const SpeexMode wideband = {
+    .mode = &wideband_mode,
+    .modeID = 1,
+    .decode = sb_decode,
+};
+
+static const SpeexMode ultrawideband = {
+    .mode = &ultrawideband_mode,
+    .modeID = 2,
+    .decode = sb_decode,
+};
+
+static const SpeexMode *const speex_modes[SPEEX_NB_MODES] = {
+    &narrowband,
+    &wideband,
+    &ultrawideband,
+};
+
+static int sb_decode(AVCodecContext *avctx, DecoderState *st,
+                     GetBitContext *gb, float *out)
+{
+    SpeexContext *s = avctx->priv_data;
+    float low_pi_gain[NB_NB_SUBFRAMES];
+    float low_exc_rms[NB_NB_SUBFRAMES];
+    float interp_qlsp[NB_ORDER];
+    int ret, wideband, dtx = 0;
+    float *low_innov_alias;
+    float qlsp[NB_ORDER];
+    float ak[NB_ORDER];
+    const SpeexBMode *mode;
+
+    mode = st->mode;
+
+    if (st->modeID > 0) {
+        low_innov_alias = out + st->frame_size;
+        s->st[st->modeID - 1].innov_save = low_innov_alias;
+        ret = speex_modes[st->modeID - 1]->decode(avctx, &s->st[st->modeID - 1], gb, out);
+        if (ret < 0)
+            return ret;
+    }
+
+    if (st->encode_submode) { /* Check "wideband bit" */
+        if (get_bits_left(gb) > 0)
+            wideband = show_bits1(gb);
+        else
+            wideband = 0;
+        if (wideband) { /* Regular wideband frame, read the submode */
+            wideband = get_bits1(gb);
+            st->submodeID = get_bits(gb, SB_SUBMODE_BITS);
+        } else { /* Was a narrowband frame, set "null submode" */
+            st->submodeID = 0;
+        }
+        if (st->submodeID != 0 && st->submodes[st->submodeID] == NULL)
+            return AVERROR_INVALIDDATA;
+    }
+
+    /* 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);
+            return 0;
+        }
+
+        for (int i = 0; i < st->frame_size; i++)
+            out[st->frame_size + i] = 1e-15f;
+
+        st->first = 1;
+
+        /* Final signal synthesis from excitation */
+        iir_mem(out + st->frame_size, st->interp_qlpc, out + st->frame_size, st->frame_size, st->lpc_size, st->mem_sp);
+
+        qmf_synth(out, out + st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem);
+
+        return 0;
+    }
+
+    memcpy(low_pi_gain, s->st[st->modeID - 1].pi_gain, sizeof(low_pi_gain));
+    memcpy(low_exc_rms, s->st[st->modeID - 1].exc_rms, sizeof(low_exc_rms));
+
+    SUBMODE(lsp_unquant)(qlsp, st->lpc_size, gb);
+
+    if (st->first)
+        memcpy(st->old_qlsp, qlsp, sizeof(st->old_qlsp));
+
+    for (int sub = 0; sub < st->nb_subframes; sub++) {
+        float filter_ratio, el, rl, rh;
+        float *innov_save = NULL, *sp;
+        float exc[80];
+        int offset;
+
+        offset = st->subframe_size * sub;
+        sp = out + st->frame_size + offset;
+        /* Pointer for saving innovation */
+        if (st->innov_save) {
+            innov_save = st->innov_save + 2 * offset;
+            SPEEX_MEMSET(innov_save, 0, 2 * st->subframe_size);
+        }
+
+        av_assert0(st->nb_subframes > 0);
+        lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpc_size, sub, st->nb_subframes, 0.05f);
+        lsp_to_lpc(interp_qlsp, ak, st->lpc_size);
+
+        /* Calculate reponse ratio between the low and high filter in the middle
+           of the band (4000 Hz) */
+        st->pi_gain[sub] = 1.f;
+        rh = 1.f;
+        for (int i = 0; i < st->lpc_size; i += 2) {
+            rh += ak[i + 1] - ak[i];
+            st->pi_gain[sub] += ak[i] + ak[i + 1];
+        }
+
+        rl = low_pi_gain[sub];
+        filter_ratio = (rl + .01f) / (rh + .01f);
+
+        SPEEX_MEMSET(exc, 0, st->subframe_size);
+        if (!SUBMODE(innovation_unquant)) {
+            const int x = get_bits(gb, 5);
+            const float g = expf(.125f * (x - 10)) / filter_ratio;
+
+            for (int i = 0; i < st->subframe_size; i += 2) {
+                exc[i    ] =  mode->folding_gain * low_innov_alias[offset + i    ] * g;
+                exc[i + 1] = -mode->folding_gain * low_innov_alias[offset + i + 1] * g;
+            }
+        } else {
+            float gc, scale;
+
+            el = low_exc_rms[sub];
+            gc = 0.87360f * gc_quant_bound[get_bits(gb, 4)];
+
+            if (st->subframe_size == 80)
+                gc *= M_SQRT2;
+
+            scale = (gc * el) / filter_ratio;
+            SUBMODE(innovation_unquant)
+                (exc, SUBMODE(innovation_params), st->subframe_size,
+                 gb, &st->seed);
+
+            signal_mul(exc, exc, scale, st->subframe_size);
+            if (SUBMODE(double_codebook)) {
+                float innov2[80];
+
+                SPEEX_MEMSET(innov2, 0, st->subframe_size);
+                SUBMODE(innovation_unquant)(innov2, SUBMODE(innovation_params), st->subframe_size, gb, &st->seed);
+                signal_mul(innov2, innov2, 0.4f * scale, st->subframe_size);
+                for (int i = 0; i < st->subframe_size; i++)
+                    exc[i] += innov2[i];
+            }
+        }
+
+        if (st->innov_save) {
+            for (int i = 0; i < st->subframe_size; i++)
+                innov_save[2 * i] = exc[i];
+        }
+
+        iir_mem(st->exc_buf, st->interp_qlpc, sp, st->subframe_size, st->lpc_size, st->mem_sp);
+        memcpy(st->exc_buf, exc, sizeof(exc));
+        memcpy(st->interp_qlpc, ak, sizeof(st->interp_qlpc));
+        st->exc_rms[sub] = compute_rms(st->exc_buf, st->subframe_size);
+    }
+
+    qmf_synth(out, out + st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem);
+    memcpy(st->old_qlsp, qlsp, sizeof(st->old_qlsp));
+
+    st->first = 0;
+
+    return 0;
+}
+
+static int decoder_init(SpeexContext *s, DecoderState *st, const SpeexMode *m)
+{
+    const SpeexBMode *mode;
+
+    mode = m->mode;
+    st->mode = mode;
+    st->modeID = m->modeID;
+
+    st->first = 1;
+    st->encode_submode = 1;
+    st->is_wideband = st->modeID > 0;
+    st->innov_save = NULL;
+
+    st->submodes = mode->submodes;
+    st->submodeID = mode->default_submode;
+    st->subframe_size = mode->subframe_size;
+    st->lpc_size = mode->lpc_size;
+    st->full_frame_size = (1 + (st->modeID > 0)) * mode->frame_size;
+    st->nb_subframes = mode->frame_size / mode->subframe_size;
+    st->frame_size = mode->frame_size;
+
+    st->lpc_enh_enabled = 1;
+
+    st->last_pitch = 40;
+    st->count_lost = 0;
+    st->seed = 1000;
+    st->last_ol_gain = 0;
+
+    st->voc_m1 = st->voc_m2 = st->voc_mean = 0;
+    st->voc_offset = 0;
+    st->dtx_enabled = 0;
+    st->highpass_enabled = m->modeID == 0;
+
+    return 0;
+}
+
+static int parse_speex_extradata(AVCodecContext *avctx,
+    const uint8_t *extradata, int extradata_size)
+{
+    SpeexContext *s = avctx->priv_data;
+    const uint8_t *buf = extradata;
+    uint8_t header[8];
+
+    bytestream_get_buffer(&buf, header, sizeof(header));
+
+    if (memcmp(header, "Speex   ", sizeof(header)))
+        return AVERROR_INVALIDDATA;
+
+    buf += 20;
+
+    s->version_id = bytestream_get_le32(&buf);
+    buf += 4;
+    s->rate = bytestream_get_le32(&buf);
+    if (s->rate <= 0)
+        return AVERROR_INVALIDDATA;
+    s->mode = bytestream_get_le32(&buf);
+    if (s->mode < 0 || s->mode >= SPEEX_NB_MODES)
+        return AVERROR_INVALIDDATA;
+    s->bitstream_version = bytestream_get_le32(&buf);
+    if (s->bitstream_version != 4)
+        return AVERROR_INVALIDDATA;
+    s->nb_channels = bytestream_get_le32(&buf);
+    if (s->nb_channels <= 0 || s->nb_channels > 2)
+        return AVERROR_INVALIDDATA;
+    s->bitrate = bytestream_get_le32(&buf);
+    s->frame_size = bytestream_get_le32(&buf);
+    if (s->frame_size < NB_FRAME_SIZE)
+        return AVERROR_INVALIDDATA;
+    s->vbr = bytestream_get_le32(&buf);
+    s->frames_per_packet = bytestream_get_le32(&buf);
+    if (s->frames_per_packet <= 0)
+        return AVERROR_INVALIDDATA;
+    s->extra_headers = bytestream_get_le32(&buf);
+
+    return 0;
+}
+
+static av_cold int speex_decode_init(AVCodecContext *avctx)
+{
+    SpeexContext *s = avctx->priv_data;
+    int ret;
+
+    if (avctx->extradata && avctx->extradata_size >= 80) {
+        ret = parse_speex_extradata(avctx, avctx->extradata, avctx->extradata_size);
+        if (ret < 0)
+            return ret;
+    }
+
+    if (avctx->codec_tag == MKTAG('S', 'P', 'X', 'N')) {
+        int quality;
+
+        if (!avctx->extradata || avctx->extradata && avctx->extradata_size < 47) {
+            av_log(avctx, AV_LOG_ERROR, "Missing or invalid extradata.\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        quality = avctx->extradata[37];
+        if (quality > 10) {
+            av_log(avctx, AV_LOG_ERROR, "Unsupported quality mode %d.\n", quality);
+            return AVERROR_PATCHWELCOME;
+        }
+
+        s->pkt_size = ((const uint8_t[]){ 5, 10, 15, 20, 20, 28, 28, 38, 38, 46, 62 })[quality];
+
+        s->mode = 0;
+        s->nb_channels = 1;
+        s->rate = avctx->sample_rate;
+        if (s->rate <= 0)
+            return AVERROR_INVALIDDATA;
+        s->frames_per_packet = 1;
+        s->frame_size = NB_FRAME_SIZE;
+    }
+
+    if (s->bitrate > 0)
+        avctx->bit_rate = s->bitrate;
+    avctx->channels = s->nb_channels;
+    avctx->sample_rate = s->rate;
+    avctx->sample_fmt = AV_SAMPLE_FMT_FLT;
+
+    for (int m = 0; m <= s->mode; m++) {
+        ret = decoder_init(s, &s->st[m], speex_modes[m]);
+        if (ret < 0)
+            return ret;
+    }
+
+    s->stereo.balance = 1.f;
+    s->stereo.e_ratio = .5f;
+    s->stereo.smooth_left = 1.f;
+    s->stereo.smooth_right = 1.f;
+
+    return 0;
+}
+
+static void speex_decode_stereo(float *data, int frame_size, StereoState *stereo)
+{
+    float balance, e_left, e_right, e_ratio;
+
+    balance = stereo->balance;
+    e_ratio = stereo->e_ratio;
+
+    /* These two are Q14, with max value just below 2. */
+    e_right = 1.f / sqrtf(e_ratio * (1.f + balance));
+    e_left = sqrtf(balance) * e_right;
+
+    for (int i = frame_size - 1; i >= 0; i--) {
+        float tmp = data[i];
+        stereo->smooth_left  = stereo->smooth_left  * 0.98f + e_left  * 0.02f;
+        stereo->smooth_right = stereo->smooth_right * 0.98f + e_right * 0.02f;
+        data[2 * i    ] = stereo->smooth_left  * tmp;
+        data[2 * i + 1] = stereo->smooth_right * tmp;
+    }
+}
+
+static int speex_decode_frame(AVCodecContext *avctx, void *data,
+                              int *got_frame_ptr, AVPacket *avpkt)
+{
+    SpeexContext *s = avctx->priv_data;
+    AVFrame *frame = data;
+    const float scale = 1.f / 32768.f;
+    int buf_size = avpkt->size;
+    float *dst;
+    int ret;
+
+    if (s->pkt_size && avpkt->size == 62)
+        buf_size = s->pkt_size;
+    if ((ret = init_get_bits8(&s->gb, avpkt->data, buf_size)) < 0)
+        return ret;
+
+    frame->nb_samples = s->frame_size * s->frames_per_packet;
+    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+        return ret;
+
+    dst = (float *)frame->extended_data[0];
+    for (int i = 0; i < s->frames_per_packet; i++) {
+        ret = speex_modes[s->mode]->decode(avctx, &s->st[s->mode], &s->gb, dst + i * s->frame_size);
+        if (ret < 0)
+            return ret;
+        if (avctx->channels == 2)
+            speex_decode_stereo(dst + i * s->frame_size, s->frame_size, &s->stereo);
+    }
+
+    dst = (float *)frame->extended_data[0];
+    for (int n = 0; n < frame->nb_samples * avctx->channels; n++)
+        dst[n] *= scale;
+
+    *got_frame_ptr = 1;
+
+    return buf_size;
+}
+
+const AVCodec ff_speex_decoder = {
+    .name           = "speex",
+    .long_name      = NULL_IF_CONFIG_SMALL("Speex"),
+    .type           = AVMEDIA_TYPE_AUDIO,
+    .id             = AV_CODEC_ID_SPEEX,
+    .init           = speex_decode_init,
+    .decode         = speex_decode_frame,
+    .capabilities   = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF,
+    .priv_data_size = sizeof(SpeexContext),
+    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
+};
-- 
2.17.1



More information about the ffmpeg-devel mailing list