aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--include/osmocom/gmr1/Makefile.am2
-rw-r--r--include/osmocom/gmr1/codec/Makefile.am2
-rw-r--r--include/osmocom/gmr1/codec/codec.h50
-rw-r--r--src/Makefile.am7
-rw-r--r--src/codec/Makefile.am8
-rw-r--r--src/codec/ambe.c140
-rw-r--r--src/codec/codec.c103
-rw-r--r--src/codec/frame.c205
-rw-r--r--src/codec/math.c108
-rw-r--r--src/codec/mbelib.c517
-rw-r--r--src/codec/mbelib.h51
-rw-r--r--src/codec/private.h133
-rw-r--r--src/codec/tables.c1134
-rw-r--r--src/codec/tone.c210
-rw-r--r--src/gmr1_ambe_decode.c195
16 files changed, 2864 insertions, 3 deletions
diff --git a/configure.ac b/configure.ac
index 60c850b..5fc0560 100644
--- a/configure.ac
+++ b/configure.ac
@@ -45,9 +45,11 @@ AC_OUTPUT(
include/Makefile
include/osmocom/Makefile
include/osmocom/gmr1/Makefile
+ include/osmocom/gmr1/codec/Makefile
include/osmocom/gmr1/l1/Makefile
include/osmocom/gmr1/sdr/Makefile
src/Makefile
+ src/codec/Makefile
src/l1/Makefile
src/sdr/Makefile
Makefile
diff --git a/include/osmocom/gmr1/Makefile.am b/include/osmocom/gmr1/Makefile.am
index 91c5c44..c6d331f 100644
--- a/include/osmocom/gmr1/Makefile.am
+++ b/include/osmocom/gmr1/Makefile.am
@@ -1,3 +1,3 @@
-SUBDIRS = l1 sdr
+SUBDIRS = codec l1 sdr
noinst_HEADERS = gsmtap.h
diff --git a/include/osmocom/gmr1/codec/Makefile.am b/include/osmocom/gmr1/codec/Makefile.am
new file mode 100644
index 0000000..e6e9cdc
--- /dev/null
+++ b/include/osmocom/gmr1/codec/Makefile.am
@@ -0,0 +1,2 @@
+noinst_HEADERS = \
+ codec.h
diff --git a/include/osmocom/gmr1/codec/codec.h b/include/osmocom/gmr1/codec/codec.h
new file mode 100644
index 0000000..ff92e89
--- /dev/null
+++ b/include/osmocom/gmr1/codec/codec.h
@@ -0,0 +1,50 @@
+/* GMR-1 AMBE vocoder */
+
+/* (C) 2013 by Sylvain Munaut <tnt@246tNt.com>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __OSMO_GMR1_CODEC_H__
+#define __OSMO_GMR1_CODEC_H__
+
+/*! \defgroup codec AMBE vocoder
+ * \ingroup codec
+ * @{
+ */
+
+/*! \file codec/codec.h
+ * \brief Osmocom GMR-1 AMBE vocoder header
+ */
+
+#include <stdint.h>
+
+
+struct gmr1_codec;
+
+struct gmr1_codec *gmr1_codec_alloc(void);
+void gmr1_codec_release(struct gmr1_codec *codec);
+
+int gmr1_codec_decode_frame(struct gmr1_codec *codec,
+ int16_t *audio, int N,
+ const uint8_t *frame, int bad);
+
+int gmr1_codec_decode_dtx(struct gmr1_codec *codec,
+ int16_t *audio, int N);
+
+
+/*! @} */
+
+#endif /* __OSMO_GMR1_CODEC_H__ */
diff --git a/src/Makefile.am b/src/Makefile.am
index 7887412..bedaad0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,10 +1,10 @@
-SUBDIRS = l1 sdr
+SUBDIRS = codec l1 sdr
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMODSP_CFLAGS)
AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMODSP_LIBS)
-bin_PROGRAMS = gmr1_rx gmr1_gen_mat
+bin_PROGRAMS = gmr1_rx gmr1_gen_mat gmr1_ambe_decode
gmr1_rx_SOURCES = gmr1_rx.c gsmtap.c
gmr1_rx_LDADD = $(top_builddir)/src/l1/libgmr1-l1.a \
@@ -13,3 +13,6 @@ gmr1_rx_LDADD = $(top_builddir)/src/l1/libgmr1-l1.a \
gmr1_gen_mat_SOURCES = gmr1_gen_mat.c
gmr1_gen_mat_LDADD = $(top_builddir)/src/l1/libgmr1-l1.a
+
+gmr1_ambe_decode_SOURCES = gmr1_ambe_decode.c
+gmr1_ambe_decode_LDADD = $(top_builddir)/src/codec/libgmr1-codec.a
diff --git a/src/codec/Makefile.am b/src/codec/Makefile.am
new file mode 100644
index 0000000..bdecf58
--- /dev/null
+++ b/src/codec/Makefile.am
@@ -0,0 +1,8 @@
+AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
+AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS)
+AM_LDFLAGS = $(LIBOSMOCORE_LIBS)
+
+noinst_LIBRARIES = libgmr1-codec.a
+
+libgmr1_codec_a_SOURCES = \
+ ambe.c codec.c frame.c math.c mbelib.c tables.c tone.c
diff --git a/src/codec/ambe.c b/src/codec/ambe.c
new file mode 100644
index 0000000..ea46b20
--- /dev/null
+++ b/src/codec/ambe.c
@@ -0,0 +1,140 @@
+/* GMR-1 AMBE vocoder - internal API */
+
+/* (C) 2013 by Sylvain Munaut <tnt@246tNt.com>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*! \addtogroup codec/private
+ * @{
+ */
+
+/*! \file codec/ambe.c
+ * \brief Osmocom GMR-1 AMBE internal API
+ */
+
+#include <errno.h>
+#include <math.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "private.h"
+
+
+void
+ambe_decode_init(struct ambe_decoder *dec)
+{
+ memset(dec, 0x00, sizeof(struct ambe_decoder));
+ mbe_initMbeParms(&dec->mp_cur, &dec->mp_prev, &dec->mp_prev_enh);
+}
+
+void
+ambe_decode_fini(struct ambe_decoder *dec)
+{
+ /* nothing to do */
+}
+
+
+static enum ambe_frame_type
+ambe_classify_frame(const uint8_t *frame)
+{
+ switch (frame[0] & 0xfc) {
+ case 0xfc:
+ return AMBE_TONE;
+
+ case 0xf8:
+ return AMBE_SILENCE;
+
+ default:
+ return AMBE_SPEECH;
+ };
+}
+
+static int
+ambe_decode_speech(struct ambe_decoder *dec,
+ int16_t *audio, int N,
+ const uint8_t *frame, int bad)
+{
+ struct ambe_raw_params rp;
+ struct ambe_subframe sf[2];
+ float unvc;
+ int i;
+
+ /* Unpack frame */
+ ambe_frame_unpack_raw(&rp, frame);
+
+ /* Decode subframe parameters */
+ ambe_frame_decode_params(sf, &dec->sf_prev, &rp);
+
+ /* Convert to mbelib's format */
+ dec->mp_cur.w0 = sf[1].f0 * (2.0f * (float)M_PI);
+ dec->mp_cur.L = sf[1].L;
+
+ unvc = 0.2046f / sqrtf(dec->mp_cur.w0); /* ??? */
+
+ for (i=1; i<=dec->mp_cur.L; i++) {
+ int j = (int)((i-1) * 16.0f * sf[1].f0);
+ dec->mp_cur.Vl[i] = sf[1].v_uv[j];
+ dec->mp_cur.Ml[i] = powf(2.0, sf[1].Mlog[i-1]) / 8.0f;
+ if (!dec->mp_cur.Vl[i])
+ dec->mp_cur.Ml[i] *= unvc;
+ }
+
+ /* Synthesize speech (using mbelib for now) */
+ mbe_moveMbeParms(&dec->mp_cur, &dec->mp_prev);
+ mbe_spectralAmpEnhance(&dec->mp_cur);
+ mbe_synthesizeSpeech(audio, &dec->mp_cur, &dec->mp_prev_enh, 2);
+ mbe_moveMbeParms(&dec->mp_cur, &dec->mp_prev_enh);
+
+ /* Save subframe */
+ memcpy(&dec->sf_prev, &sf[1], sizeof(struct ambe_subframe));
+
+ /* Done */
+ return 0;
+}
+
+int
+ambe_decode_frame(struct ambe_decoder *dec,
+ int16_t *audio, int N,
+ const uint8_t *frame, int bad)
+{
+ switch(ambe_classify_frame(frame)) {
+ case AMBE_SPEECH:
+ return ambe_decode_speech(dec, audio, N, frame, bad);
+
+ case AMBE_SILENCE:
+ /* FIXME: Comfort noise */
+ memset(audio, 0, 160*sizeof(int16_t));
+ return 0;
+
+ case AMBE_TONE:
+ /* FIXME: Tone gen */
+ memset(audio, 0, 160*sizeof(int16_t));
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+int
+ambe_decode_dtx(struct ambe_decoder *dec,
+ int16_t *audio, int N)
+{
+ /* FIXME: Comfort noise */
+ memset(audio, 0x00, sizeof(int16_t) * N);
+ return 0;
+}
+
+/*! @} */
diff --git a/src/codec/codec.c b/src/codec/codec.c
new file mode 100644
index 0000000..c422b5b
--- /dev/null
+++ b/src/codec/codec.c
@@ -0,0 +1,103 @@
+/* GMR-1 AMBE vocoder */
+
+/* (C) 2013 by Sylvain Munaut <tnt@246tNt.com>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*! \addtogroup codec
+ * @{
+ */
+
+/*! \file codec/codec.c
+ * \brief Osmocom GMR-1 AMBE vocoder public API implementation
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <osmocom/gmr1/codec/codec.h>
+
+#include "private.h"
+
+
+/*! \brief Structure for GMR1 codec state */
+struct gmr1_codec
+{
+ struct ambe_decoder dec; /*< \brief decoder state */
+};
+
+
+/*! \brief Allocates and inits a codec object
+ * \returns A newly allocated codec, to be freed with \ref gmr1_codec_release
+ */
+struct gmr1_codec *
+gmr1_codec_alloc(void)
+{
+ struct gmr1_codec *codec;
+
+ codec = calloc(1, sizeof(struct gmr1_codec));
+ if (!codec)
+ return NULL;
+
+ ambe_decode_init(&codec->dec);
+
+ return codec;
+}
+
+/*! \brief Release a codec object created by \ref gmr1_codec_alloc
+ * \param[in] codec The codec object to release
+ */
+void
+gmr1_codec_release(struct gmr1_codec *codec)
+{
+ if (!codec)
+ return;
+
+ ambe_decode_fini(&codec->dec);
+
+ free(codec);
+}
+
+/*! \brief Decodes an AMBE frame to audio
+ * \param[in] codec Codec object
+ * \param[out] audio Output audio buffer
+ * \param[in] N number of audio samples to produce (152..168)
+ * \param[in] frame Frame data (10 bytes = 80 bits)
+ * \param[in] bad Bad Frame Indicator. Set to 1 if frame is corrupt
+ * \returns 0 for success. Negative error code otherwise.
+ */
+int
+gmr1_codec_decode_frame(struct gmr1_codec *codec,
+ int16_t *audio, int N,
+ const uint8_t *frame, int bad)
+{
+ return ambe_decode_frame(&codec->dec, audio, N, frame, bad);
+}
+
+/*! \brief Generates audio for DTX period
+ * \param[in] codec Codec object
+ * \param[out] audio Output audio buffer
+ * \param[in] N number of audio samples to produce (152..168)
+ */
+int
+gmr1_codec_decode_dtx(struct gmr1_codec *codec,
+ int16_t *audio, int N)
+{
+ return ambe_decode_dtx(&codec->dec, audio, N);
+}
+
+/*! @} */
diff --git a/src/codec/frame.c b/src/codec/frame.c
new file mode 100644
index 0000000..9c6ee0f
--- /dev/null
+++ b/src/codec/frame.c
@@ -0,0 +1,205 @@
+/* GMR-1 AMBE vocoder - Speech parameters to/from frame */
+
+/* (C) 2013 by Sylvain Munaut <tnt@246tNt.com>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*! \addtogroup codec/private
+ * @{
+ */
+
+/*! \file codec/frame.c
+ * \brief Osmocom GMR-1 AMBE speech parameters to/from frame
+ */
+
+#include <math.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "private.h"
+
+
+static inline uint8_t
+_get_bits(const uint8_t *frame, int p, int l, int s)
+{
+ uint8_t v;
+
+ if ((p & 7) + l > 8) {
+ v = ((frame[p>>3] << 8) | frame[(p>>3)+1]) >> (16 - (p&7) - l);
+ } else {
+ v = frame[p>>3] >> (8 - (p&7) - l);
+ }
+
+ return (v & ((1<<l)-1)) << s;
+}
+
+void
+ambe_frame_unpack_raw(struct ambe_raw_params *rp, const uint8_t *frame)
+{
+ const uint8_t *p = frame;
+
+ rp->pitch = _get_bits(p, 0, 7, 0);
+ rp->pitch_interp = _get_bits(p, 48, 2, 0);
+ rp->gain = _get_bits(p, 7, 6, 2) | _get_bits(p, 50, 2, 0);
+ rp->v_uv = _get_bits(p, 13, 6, 0);
+ rp->sf1_prba12 = _get_bits(p, 19, 6, 1) | _get_bits(p, 52, 1, 0);
+ rp->sf1_prba34 = _get_bits(p, 25, 3, 3) | _get_bits(p, 53, 3, 0);
+ rp->sf1_prba57 = _get_bits(p, 28, 3, 4) | _get_bits(p, 56, 4, 0);
+ rp->sf1_hoc[0] = _get_bits(p, 31, 3, 4) | _get_bits(p, 60, 4, 0);
+ rp->sf1_hoc[1] = _get_bits(p, 34, 3, 3) | _get_bits(p, 64, 3, 0);
+ rp->sf1_hoc[2] = _get_bits(p, 37, 2, 4) | _get_bits(p, 67, 4, 0);
+ rp->sf1_hoc[3] = _get_bits(p, 39, 2, 3) | _get_bits(p, 71, 3, 0);
+ rp->sf0_mag_interp = _get_bits(p, 46, 2, 0);
+ rp->sf0_perr_14 = _get_bits(p, 41, 3, 3) | _get_bits(p, 74, 3, 0);
+ rp->sf0_perr_58 = _get_bits(p, 44, 2, 3) | _get_bits(p, 77, 3, 0);
+}
+
+int
+ambe_frame_decode_params(struct ambe_subframe *sf,
+ struct ambe_subframe *sf_prev,
+ struct ambe_raw_params *rp)
+{
+ uint16_t v_uv;
+ int i;
+
+ /* w0 : fundamental */
+ sf[1].f0 = powf(2.0, -4.312 - 2.1336e-2 * (rp->pitch /* + 0.5 */));
+
+ /* FIXME: sf[0] interpolation */
+
+ /* Harmonics count (total and per-block) */
+ sf[1].L = (int)floorf(0.4761f / sf[1].f0);
+
+ if (sf[1].L < 9)
+ sf[1].L = 9;
+ else if (sf[1].L > 56)
+ sf[1].L = 56;
+
+ sf[1].Lb[0] = ambe_hpg_tbl[sf[1].L - 9][0];
+ sf[1].Lb[1] = ambe_hpg_tbl[sf[1].L - 9][1];
+ sf[1].Lb[2] = ambe_hpg_tbl[sf[1].L - 9][2];
+ sf[1].Lb[3] = ambe_hpg_tbl[sf[1].L - 9][3];
+
+ /* Voicing decision */
+ v_uv = ambe_v_uv_tbl[rp->v_uv];
+
+ for (i=0; i<8; i++) {
+ sf[0].v_uv[i] = (v_uv >> ( 7-i)) & 1;
+ sf[1].v_uv[i] = (v_uv >> (15-i)) & 1;
+ }
+
+ /* Gain */
+ float gain = ambe_gain_tbl[rp->gain][1];
+
+ gain += 0.5f * sf_prev->gain;
+ if (gain > 13.0f)
+ gain = 13.0f;
+ sf[1].gain = gain;
+
+ gain -= 0.5f * log2f(sf[1].L);
+
+ /* Prediction */
+ {
+ float avg, step, pos;
+
+ avg = 0.0f;
+ step = (float)sf_prev->L / (float)sf[1].L;
+ pos = step;
+
+ for (i=0; i<sf[1].L; i++)
+ {
+ int posi = (int)floorf(pos);
+
+ if (posi == 0) {
+ sf[1].Mlog[i] = sf_prev->Mlog[0];
+ } else if (posi >= sf_prev->L) {
+ sf[1].Mlog[i] = sf_prev->Mlog[sf_prev->L-1];
+ } else {
+ float alpha = pos - posi;
+ sf[1].Mlog[i] =
+ sf_prev->Mlog[posi-1] * (1.0f - alpha) +
+ sf_prev->Mlog[posi] * alpha;
+ }
+
+ avg += sf[1].Mlog[i];
+ pos += step;
+ }
+
+ avg /= sf[1].L;
+
+ for (i=0; i<sf[1].L; i++)
+ sf[1].Mlog[i] = 0.65f * (sf[1].Mlog[i] - avg);
+ }
+
+ /* PRBA */
+ float prba[8];
+ float Ri[8];
+
+ prba[0] = 0.0f;
+ prba[1] = ambe_prba12_tbl[rp->sf1_prba12][0];
+ prba[2] = ambe_prba12_tbl[rp->sf1_prba12][1];
+ prba[3] = ambe_prba34_tbl[rp->sf1_prba34][0];
+ prba[4] = ambe_prba34_tbl[rp->sf1_prba34][1];
+ prba[5] = ambe_prba57_tbl[rp->sf1_prba57][0];
+ prba[6] = ambe_prba57_tbl[rp->sf1_prba57][1];
+ prba[7] = ambe_prba57_tbl[rp->sf1_prba57][2];
+
+ ambe_idct(Ri, prba, 8, 8);
+
+ /* Process each block */
+ float rconst = (1.0f / (2.0f * (float)M_SQRT2));
+ float sum = 0.0f;
+ int j=0;
+ int k;
+
+ for (i=0; i<4; i++) {
+ const float *hoc_tbl[] = {
+ ambe_hoc0_tbl[rp->sf1_hoc[0]],
+ ambe_hoc1_tbl[rp->sf1_hoc[1]],
+ ambe_hoc2_tbl[rp->sf1_hoc[2]],
+ ambe_hoc3_tbl[rp->sf1_hoc[3]],
+ };
+ float C[6], c[17];
+
+ /* From PRBA through 2x2 xform */
+ C[0] = (Ri[i<<1] + Ri[(i<<1)+1]) * 0.5f;
+ C[1] = (Ri[i<<1] - Ri[(i<<1)+1]) * rconst;
+
+ /* HOC */
+ C[2] = hoc_tbl[i][0];
+ C[3] = hoc_tbl[i][1];
+ C[4] = hoc_tbl[i][2];
+ C[5] = hoc_tbl[i][3];
+
+ /* De-DCT */
+ ambe_idct(c, C, sf[1].Lb[i], 6);
+
+ /* Set magnitudes */
+ for (k=0; k<sf[1].Lb[i]; k++)
+ sf[1].Mlog[j++] += c[k];
+
+ sum += C[0] * sf[1].Lb[i];
+ }
+
+ float g = gain - (sum / sf[1].L);
+
+ for (i=0; i<sf[1].L; i++)
+ sf[1].Mlog[i] += g;
+
+ return 0;
+}
+
+/*! @} */
diff --git a/src/codec/math.c b/src/codec/math.c
new file mode 100644
index 0000000..334677a
--- /dev/null
+++ b/src/codec/math.c
@@ -0,0 +1,108 @@
+/* GMR-1 AMBE vocoder - Math functions */
+
+/* (C) 2013 by Sylvain Munaut <tnt@246tNt.com>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*! \addtogroup codec/private
+ * @{
+ */
+
+/*! \file codec/math.c
+ * \brief Osmocom GMR-1 AMBE vocoder math functions
+ */
+
+#include <math.h>
+
+
+#define M_PIf ((float)M_PI) /*!< \brief Value of pi as a float */
+
+
+/*! \brief Table for \ref cosf_fast */
+static float cos_tbl[1024];
+
+/*! \brief Initializes \ref cos_tbl for \ref cosf_fast */
+static void __attribute__ ((constructor))
+cos_tbl_init(void)
+{
+ int i;
+
+ for (i=0; i<1024; i++)
+ cos_tbl[i] = cosf((M_PIf * i) / 512.0f);
+}
+
+/*! \brief Fast Cosinus approximation using a simple table
+ * \param[in] angle The angle value
+ * \returns The cosinus of the angle
+ */
+float
+cosf_fast(float angle)
+{
+ const float f = 512.0f / M_PIf;
+ return cos_tbl[(int)(angle*f) & 1023];
+}
+
+
+/*! \brief Forward Discrete Cosine Transform (fDCT)
+ * \param[out] out fDCT result buffer (freq domain, M elements)
+ * \param[in] in fDCT input buffer (time domain, N elements)
+ * \param[in] N Number of points of the DCT
+ * \param[in] M Limit to the number of frequency components (M <= N)
+ */
+void
+ambe_fdct(float *out, float *in, int N, int M)
+{
+ int i, j;
+
+ for (i=0; i<M; i++)
+ {
+ float v = 0.0f;
+
+ for (j=0; j<N; j++)
+ {
+ v += in[j] * cosf_fast( (M_PIf / N) * (j + .5f) * i );
+ }
+
+ out[i] = v / (float)N;
+ }
+}
+
+
+/*! \brief Inverse Discrete Cosine Transform (iDCT)
+ * \param[out] out iDCT result buffer (time domain, N elements)
+ * \param[in] in iDCT input buffer (freq domain, M elements)
+ * \param[in] N Number of points of the DCT
+ * \param[in] M Limit to the number of frequency components (M <= N)
+ */
+void
+ambe_idct(float *out, float *in, int N, int M)
+{
+ int i, j;
+
+ for (i=0; i<N; i++)
+ {
+ float v = in[0];
+
+ for (j=1; j<M; j++)
+ {
+ v += 2.0f * in[j] * cosf_fast( (M_PIf / N) * j * (i + .5f) );
+ }
+
+ out[i] = v;
+ }
+}
+
+/*! @} */
diff --git a/src/codec/mbelib.c b/src/codec/mbelib.c
new file mode 100644
index 0000000..d6561f4
--- /dev/null
+++ b/src/codec/mbelib.c
@@ -0,0 +1,517 @@
+/*
+ * Copyright (C) 2010 mbelib Author
+ * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C)
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "mbelib.h"
+#include "private.h"
+
+
+/*
+ * Speech Synthesis Window 8k version
+ */
+static const float Ws[321] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0.02, 0.04, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18,
+ 0.2, 0.22, 0.24, 0.26, 0.28, 0.3, 0.32, 0.34, 0.36, 0.38,
+ 0.4, 0.42, 0.44, 0.46, 0.48, 0.5, 0.52, 0.54, 0.56, 0.58,
+ 0.6, 0.62, 0.64, 0.66, 0.68, 0.7, 0.72, 0.74, 0.76, 0.78,
+ 0.8, 0.82, 0.84, 0.86, 0.88, 0.9, 0.92, 0.94, 0.96, 0.98,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0.98, 0.96, 0.94, 0.92, 0.9, 0.88, 0.86, 0.84, 0.82, 0.8,
+ 0.78, 0.76, 0.74, 0.72, 0.7, 0.68, 0.66, 0.64, 0.62, 0.6,
+ 0.58, 0.56, 0.54, 0.52, 0.5, 0.48, 0.46, 0.44, 0.42, 0.4,
+ 0.38, 0.36, 0.34, 0.32, 0.3, 0.28, 0.26, 0.24, 0.22, 0.2,
+ 0.18, 0.16, 0.14, 0.12, 0.1, 0.08, 0.06, 0.04, 0.02, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+void
+mbe_printVersion (char *str)
+{
+ sprintf (str, "%s", MBELIB_VERSION);
+}
+
+void
+mbe_moveMbeParms (mbe_parms * cur_mp, mbe_parms * prev_mp)
+{
+
+ int l;
+
+ prev_mp->w0 = cur_mp->w0;
+ prev_mp->L = cur_mp->L;
+ prev_mp->K = cur_mp->K; // necessary?
+ prev_mp->Ml[0] = (float) 0;
+ prev_mp->gamma = cur_mp->gamma;
+ prev_mp->repeat = cur_mp->repeat;
+ for (l = 0; l <= 56; l++)
+ {
+ prev_mp->Ml[l] = cur_mp->Ml[l];
+ prev_mp->Vl[l] = cur_mp->Vl[l];
+ prev_mp->log2Ml[l] = cur_mp->log2Ml[l];
+ prev_mp->PHIl[l] = cur_mp->PHIl[l];
+ prev_mp->PSIl[l] = cur_mp->PSIl[l];
+ }
+}
+
+void
+mbe_useLastMbeParms (mbe_parms * cur_mp, mbe_parms * prev_mp)
+{
+
+ int l;
+
+ cur_mp->w0 = prev_mp->w0;
+ cur_mp->L = prev_mp->L;
+ cur_mp->K = prev_mp->K; // necessary?
+ cur_mp->Ml[0] = (float) 0;
+ cur_mp->gamma = prev_mp->gamma;
+ cur_mp->repeat = prev_mp->repeat;
+ for (l = 0; l <= 56; l++)
+ {
+ cur_mp->Ml[l] = prev_mp->Ml[l];
+ cur_mp->Vl[l] = prev_mp->Vl[l];
+ cur_mp->log2Ml[l] = prev_mp->log2Ml[l];
+ cur_mp->PHIl[l] = prev_mp->PHIl[l];
+ cur_mp->PSIl[l] = prev_mp->PSIl[l];
+ }
+}
+
+void
+mbe_initMbeParms (mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced)
+{
+
+ int l;
+
+ prev_mp->w0 = 0.09378;
+ prev_mp->L = 30;
+ prev_mp->K = 10;
+ prev_mp->gamma = (float) 0;
+ for (l = 0; l <= 56; l++)
+ {
+ prev_mp->Ml[l] = (float) 0;
+ prev_mp->Vl[l] = 0;
+ prev_mp->log2Ml[l] = (float) 0; // log2 of 1 == 0
+ prev_mp->PHIl[l] = (float) 0;
+ prev_mp->PSIl[l] = (M_PI / (float) 2);
+ }
+ prev_mp->repeat = 0;
+ mbe_moveMbeParms (prev_mp, cur_mp);
+ mbe_moveMbeParms (prev_mp, prev_mp_enhanced);
+}
+
+void
+mbe_spectralAmpEnhance (mbe_parms * cur_mp)
+{
+
+ float Rm0, Rm1, R2m0, R2m1, Wl[57];
+ int l;
+ float sum, gamma, M;
+
+ Rm0 = 0;
+ Rm1 = 0;
+ for (l = 1; l <= cur_mp->L; l++)
+ {
+ Rm0 = Rm0 + powf (cur_mp->Ml[l], (float) 2);
+ Rm1 = Rm1 + (powf (cur_mp->Ml[l], (float) 2) * cosf_fast (cur_mp->w0 * (float) l));
+ }
+
+ R2m0 = powf (Rm0, (float) 2);
+ R2m1 = powf (Rm1, (float) 2);
+
+ for (l = 1; l <= cur_mp->L; l++)
+ {
+ if (cur_mp->Ml[l] != 0)
+ {
+ Wl[l] = sqrtf (cur_mp->Ml[l]) * powf ((((float) 0.96 * M_PI * ((R2m0 + R2m1) - ((float) 2 * Rm0 * Rm1 * cosf_fast (cur_mp->w0 * (float) l)))) / (cur_mp->w0 * Rm0 * (R2m0 - R2m1))), (float) 0.25);
+
+ if ((8 * l) <= cur_mp->L)
+ {
+ }
+ else if (Wl[l] > 1.2)
+ {
+ cur_mp->Ml[l] = 1.2 * cur_mp->Ml[l];
+ }
+ else if (Wl[l] < 0.5)
+ {
+ cur_mp->Ml[l] = 0.5 * cur_mp->Ml[l];
+ }
+ else
+ {
+ cur_mp->Ml[l] = Wl[l] * cur_mp->Ml[l];
+ }
+ }
+ }
+
+ // generate scaling factor
+ sum = 0;
+ for (l = 1; l <= cur_mp->L; l++)
+ {
+ M = cur_mp->Ml[l];
+ if (M < 0)
+ {
+ M = -M;
+ }
+ sum += powf (M, 2);
+ }
+ if (sum == 0)
+ {
+ gamma = (float) 1.0;
+ }
+ else
+ {
+ gamma = sqrtf (Rm0 / sum);
+ }
+
+ // apply scaling factor
+ for (l = 1; l <= cur_mp->L; l++)
+ {
+ cur_mp->Ml[l] = gamma * cur_mp->Ml[l];
+ }
+}
+
+void
+mbe_synthesizeSilencef (float *aout_buf)
+{
+
+ int n;
+ float *aout_buf_p;
+
+ aout_buf_p = aout_buf;
+ for (n = 0; n < 160; n++)
+ {
+ *aout_buf_p = (float) 0;
+ aout_buf_p++;
+ }
+}
+
+void
+mbe_synthesizeSilence (short *aout_buf)
+{
+
+ int n;
+ short *aout_buf_p;
+
+ aout_buf_p = aout_buf;
+ for (n = 0; n < 160; n++)
+ {
+ *aout_buf_p = (short) 0;
+ aout_buf_p++;
+ }
+}
+
+void
+mbe_synthesizeSpeechf (float *aout_buf, mbe_parms * cur_mp, mbe_parms * prev_mp, int uvquality)
+{
+
+ int i, l, n, maxl;
+ float *Ss, loguvquality;
+ float C1, C2, C3, C4;
+ /* float deltaphil, deltawl, thetaln, aln; */
+ int numUv;
+ float cw0, pw0, cw0l, pw0l;
+ float uvsine, uvrand, uvthreshold, uvthresholdf;
+ float uvstep, uvoffset;
+ float qfactor;
+ float rphase[64], rphase2[64];
+
+ const int N = 160;
+
+ uvthresholdf = (float) 2700;
+ uvthreshold = ((uvthresholdf * M_PI) / (float) 4000);
+
+ // voiced/unvoiced/gain settings
+ uvsine = (float) 1.3591409 *M_E;
+ uvrand = (float) 2.0;
+
+ if ((uvquality < 1) || (uvquality > 64))
+ {
+ printf ("\nmbelib: Error - uvquality must be within the range 1 - 64\n");
+ exit (1);
+ }
+
+ // calculate loguvquality
+ if (uvquality == 1)
+ {
+ loguvquality = (float) 1 / M_E;
+ }
+ else
+ {
+ loguvquality = log ((float) uvquality) / (float) uvquality;
+ }
+
+ // calculate unvoiced step and offset values
+ uvstep = (float) 1.0 / (float) uvquality;
+ qfactor = loguvquality;
+ uvoffset = (uvstep * (float) (uvquality - 1)) / (float) 2;
+
+ // count number of unvoiced bands
+ numUv = 0;
+ for (l = 1; l <= cur_mp->L; l++)
+ {
+ if (cur_mp->Vl[l] == 0)
+ {
+ numUv++;
+ }
+ }
+
+ cw0 = cur_mp->w0;
+ pw0 = prev_mp->w0;
+
+ // init aout_buf
+ Ss = aout_buf;
+ for (n = 0; n < N; n++)
+ {
+ *Ss = (float) 0;
+ Ss++;
+ }
+
+ // eq 128 and 129
+ if (cur_mp->L > prev_mp->L)
+ {
+ maxl = cur_mp->L;
+ for (l = prev_mp->L + 1; l <= maxl; l++)
+ {
+ prev_mp->Ml[l] = (float) 0;
+ prev_mp->Vl[l] = 1;
+ }
+ }
+ else
+ {
+ maxl = prev_mp->L;
+ for (l = cur_mp->L + 1; l <= maxl; l++)
+ {
+ cur_mp->Ml[l] = (float) 0;
+ cur_mp->Vl[l] = 1;
+ }
+ }
+
+ // update phil from eq 139,140
+ for (l = 1; l <= 56; l++)
+ {
+ cur_mp->PSIl[l] = prev_mp->PSIl[l] + ((pw0 + cw0) * ((float) (l * N) / (float) 2));
+ if (l <= (int) (cur_mp->L / 4))
+ {
+ cur_mp->PHIl[l] = cur_mp->PSIl[l];
+ }
+ else
+ {
+ cur_mp->PHIl[l] = cur_mp->PSIl[l] + ((numUv * ((((float) random () / (float) 2147483647) * M_PI * (float) 2) - M_PI)) / cur_mp->L);
+ }
+ }
+
+ for (l = 1; l <= maxl; l++)
+ {
+ cw0l = (cw0 * (float) l);
+ pw0l = (pw0 * (float) l);
+ if ((cur_mp->Vl[l] == 0) && (prev_mp->Vl[l] == 1))
+ {
+ Ss = aout_buf;
+ // init random phase
+ for (i = 0; i < uvquality; i++)
+ {
+ rphase[i] = ((((float) random () / (float) 2147483647) * M_PI * (float) 2) - M_PI);
+ }
+ for (n = 0; n < N; n++)
+ {
+ C1 = 0;
+ // eq 131
+ C1 = Ws[n + N] * prev_mp->Ml[l] * cosf_fast ((pw0l * (float) n) + prev_mp->PHIl[l]);
+ C3 = 0;
+ // unvoiced multisine mix
+ for (i = 0; i < uvquality; i++)
+ {
+ C3 = C3 + cosf_fast ((cw0 * (float) n * ((float) l + ((float) i * uvstep) - uvoffset)) + rphase[i]);
+ if (cw0l > uvthreshold)
+ {
+ C3 = C3 + ((cw0l - uvthreshold) * uvrand * ((float) random () / (float) 2147483647));
+ }
+ }
+ C3 = C3 * uvsine * Ws[n] * cur_mp->Ml[l] * qfactor;
+ *Ss = *Ss + C1 + C3;
+ Ss++;
+ }
+ }
+ else if ((cur_mp->Vl[l] == 1) && (prev_mp->Vl[l] == 0))
+ {
+ Ss = aout_buf;
+ // init random phase
+ for (i = 0; i < uvquality; i++)
+ {
+ rphase[i] = ((((float) random () / (float) 2147483647) * M_PI * (float) 2) - M_PI);
+ }
+ for (n = 0; n < N; n++)
+ {
+ C1 = 0;
+ // eq 132
+ C1 = Ws[n] * cur_mp->Ml[l] * cosf_fast ((cw0l * (float) (n - N)) + cur_mp->PHIl[l]);
+ C3 = 0;
+ // unvoiced multisine mix
+ for (i = 0; i < uvquality; i++)
+ {
+ C3 = C3 + cosf_fast ((pw0 * (float) n * ((float) l + ((float) i * uvstep) - uvoffset)) + rphase[i]);
+ if (pw0l > uvthreshold)
+ {
+ C3 = C3 + ((pw0l - uvthreshold) * uvrand * ((float) random () / (float) 2147483647));
+ }
+ }
+ C3 = C3 * uvsine * Ws[n + N] * prev_mp->Ml[l] * qfactor;
+ *Ss = *Ss + C1 + C3;
+ Ss++;
+ }
+ }
+ // else if (((cur_mp->Vl[l] == 1) || (prev_mp->Vl[l] == 1)) && ((l >= 8) || (fabsf (cw0 - pw0) >= ((float) 0.1 * cw0))))
+ else if ((cur_mp->Vl[l] == 1) && (prev_mp->Vl[l] == 1))
+ {
+ Ss = aout_buf;
+ for (n = 0; n < N; n++)
+ {
+ C1 = 0;
+ // eq 133-1
+ C1 = Ws[n + N] * prev_mp->Ml[l] * cosf_fast ((pw0l * (float) n) + prev_mp->PHIl[l]);
+ C2 = 0;
+ // eq 133-2
+ C2 = Ws[n] * cur_mp->Ml[l] * cosf_fast ((cw0l * (float) (n - N)) + cur_mp->PHIl[l]);
+ *Ss = *Ss + C1 + C2;
+ Ss++;
+ }
+ }
+ /*
+ // expensive and unnecessary?
+ else if ((cur_mp->Vl[l] == 1) || (prev_mp->Vl[l] == 1))
+ {
+ Ss = aout_buf;
+ // eq 137
+ deltaphil = cur_mp->PHIl[l] - prev_mp->PHIl[l] - (((pw0 + cw0) * (float) (l * N)) / (float) 2);
+ // eq 138
+ deltawl = ((float) 1 / (float) N) * (deltaphil - ((float) 2 * M_PI * (int) ((deltaphil + M_PI) / (M_PI * (float) 2))));
+ for (n = 0; n < N; n++)
+ {
+ // eq 136
+ thetaln = prev_mp->PHIl[l] + ((pw0l + deltawl) * (float) n) + (((cw0 - pw0) * ((float) (l * n * n)) / (float) (2 * N)));
+ // eq 135
+ aln = prev_mp->Ml[l] + (((float) n / (float) N) * (cur_mp->Ml[l] - prev_mp->Ml[l]));
+ // eq 134
+ *Ss = *Ss + (aln * cosf_fast (thetaln));
+ Ss++;
+ }
+ }
+ */
+ else
+ {
+ Ss = aout_buf;
+ // init random phase
+ for (i = 0; i < uvquality; i++)
+ {
+ rphase[i] = ((((float) random () / (float) 2147483647) * M_PI * (float) 2) - M_PI);
+ }
+ // init random phase
+ for (i = 0; i < uvquality; i++)
+ {
+ rphase2[i] = ((((float) random () / (float) 2147483647) * M_PI * (float) 2) - M_PI);
+ }
+ for (n = 0; n < N; n++)
+ {
+ C3 = 0;
+ // unvoiced multisine mix
+ for (i = 0; i < uvquality; i++)
+ {
+ C3 = C3 + cosf_fast ((pw0 * (float) n * ((float) l + ((float) i * uvstep) - uvoffset)) + rphase[i]);
+ if (pw0l > uvthreshold)
+ {
+ C3 = C3 + ((pw0l - uvthreshold) * uvrand * ((float) random () / (float) 2147483647));
+ }
+ }
+ C3 = C3 * uvsine * Ws[n + N] * prev_mp->Ml[l] * qfactor;
+ C4 = 0;
+ // unvoiced multisine mix
+ for (i = 0; i < uvquality; i++)
+ {
+ C4 = C4 + cosf_fast ((cw0 * (float) n * ((float) l + ((float) i * uvstep) - uvoffset)) + rphase2[i]);
+ if (cw0l > uvthreshold)
+ {
+ C4 = C4 + ((cw0l - uvthreshold) * uvrand * ((float) random () / (float) 2147483647));
+ }
+ }
+ C4 = C4 * uvsine * Ws[n] * cur_mp->Ml[l] * qfactor;
+ *Ss = *Ss + C3 + C4;
+ Ss++;
+ }
+ }
+ }
+}
+
+void
+mbe_synthesizeSpeech (short *aout_buf, mbe_parms * cur_mp, mbe_parms * prev_mp, int uvquality)
+{
+ float float_buf[160];
+
+ mbe_synthesizeSpeechf (float_buf, cur_mp, prev_mp, uvquality);
+ mbe_floattoshort (float_buf, aout_buf);
+}
+
+void
+mbe_floattoshort (float *float_buf, short *aout_buf)
+{
+
+ short *aout_buf_p;
+ float *float_buf_p;
+ int i, again;
+ float audio;
+
+ again = 7;
+ aout_buf_p = aout_buf;
+ float_buf_p = float_buf;
+ for (i = 0; i < 160; i++)
+ {
+ audio = again * *float_buf_p;
+ if (audio > 32760)
+ {
+#ifdef MBE_DEBUG
+ printf ("audio clip: %f\n", audio);
+#endif
+ audio = 32760;
+ }
+ else if (audio < -32760)
+ {
+#ifdef MBE_DEBUG
+ printf ("audio clip: %f\n", audio);
+#endif
+ audio = -32760;
+ }
+ *aout_buf_p = (short) (audio);
+ aout_buf_p++;
+ float_buf_p++;
+ }
+}
diff --git a/src/codec/mbelib.h b/src/codec/mbelib.h
new file mode 100644
index 0000000..1353bd1
--- /dev/null
+++ b/src/codec/mbelib.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010 mbelib Author
+ * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C)
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __MBELIB_H__
+#define __MBELIB_H__
+
+#define MBELIB_VERSION "1.2.5"
+
+struct mbe_parameters
+{
+ float w0;
+ int L;
+ int K;
+ int Vl[57];
+ float Ml[57];
+ float log2Ml[57];
+ float PHIl[57];
+ float PSIl[57];
+ float gamma;
+ int un;
+ int repeat;
+};
+
+typedef struct mbe_parameters mbe_parms;
+
+void mbe_printVersion (char *str);
+void mbe_moveMbeParms (mbe_parms * cur_mp, mbe_parms * prev_mp);
+void mbe_useLastMbeParms (mbe_parms * cur_mp, mbe_parms * prev_mp);
+void mbe_initMbeParms (mbe_parms * cur_mp, mbe_parms * prev_mp, mbe_parms * prev_mp_enhanced);
+void mbe_spectralAmpEnhance (mbe_parms * cur_mp);
+void mbe_synthesizeSilencef (float *aout_buf);
+void mbe_synthesizeSilence (short *aout_buf);
+void mbe_synthesizeSpeechf (float *aout_buf, mbe_parms * cur_mp, mbe_parms * prev_mp, int uvquality);
+void mbe_synthesizeSpeech (short *aout_buf, mbe_parms * cur_mp, mbe_parms * prev_mp, int uvquality);
+void mbe_floattoshort (float *float_buf, short *aout_buf);
+
+#endif /* __MBELIB_H__ */
diff --git a/src/codec/private.h b/src/codec/private.h
new file mode 100644
index 0000000..c1e0e0c
--- /dev/null
+++ b/src/codec/private.h
@@ -0,0 +1,133 @@
+/* GMR-1 AMBE vocoder private header */
+
+/* (C) 2013 by Sylvain Munaut <tnt@246tNt.com>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __OSMO_GMR1_CODEC_PRIVATE_H__
+#define __OSMO_GMR1_CODEC_PRIVATE_H__
+
+/*! \defgroup codec/private AMBE vocoder - internal API
+ * \ingroup codec/private
+ * @{
+ */
+
+/*! \file codec/private.h
+ * \brief Osmocom GMR-1 AMBE vocoder private header
+ */
+
+#include <stdint.h>
+
+#include "mbelib.h"
+
+
+#define AMBE_RATE 8000 /*< \brief AMBE sample rate */
+
+
+/*! \brief AMBE possible frame types */
+enum ambe_frame_type
+{
+ AMBE_SPEECH, /*< \brief Speed frame */
+ AMBE_SILENCE, /*< \brief Silence indication frame */
+ AMBE_TONE, /*< \brief Tone frame */
+};
+
+/*! \brief AMBE encoded frame raw parameters */
+struct ambe_raw_params
+{
+ uint8_t pitch; /*!< \brief Pitch */
+ uint8_t pitch_interp; /*!< \brief Pitch interpolation selection */
+ uint8_t gain; /*!< \brief Gain VQ */
+ uint8_t v_uv; /*!< \brief V/UV decision VQ */
+
+ uint8_t sf1_prba12; /*!< \brief sf1 PRBA[1,2] VQ */
+ uint8_t sf1_prba34; /*!< \brief sf1 PRBA[3,4] VQ */
+ uint8_t sf1_prba57; /*!< \brief sf1 PRBA[5,6,7] VQ */
+ uint8_t sf1_hoc[4]; /*!< \brief sf1 HOCs VQ */
+
+ uint8_t sf0_mag_interp; /*!< \brief sf0 mag interpolation selection */
+ uint8_t sf0_perr_14; /*!< \brief sf0 mag prediction error VQ [1,4] */
+ uint8_t sf0_perr_58; /*!< \brief sf0 mag prediction error VQ [5,8] */
+};
+
+/*! \brief AMBE subframe parameters */
+struct ambe_subframe
+{
+ float f0; /*!< \brief fundamental normalized frequency */
+ int L; /*!< \brief Number of harmonics */
+ int Lb[4]; /*!< \brief Harmonics per block */
+ int v_uv[8]; /*!< \brief Voicing state */
+ float gain; /*!< \brief Gain */
+ float Mlog[56]; /*!< \brief log spectral magnitudes */
+};
+
+/*! \brief AMBE decoder state */
+struct ambe_decoder
+{
+ float tone_phase_f1; /*!< \brief Phase frequency 1 for tone frames */
+ float tone_phase_f2; /*!< \brief Phase frequency 2 for tone frames */
+
+ struct ambe_subframe sf_prev; /*!< \brief Previous subframe */
+
+ mbe_parms mp_cur; /*!< \brief mbelib current frame */
+ mbe_parms mp_prev; /*!< \brief mbelib previous frame */
+ mbe_parms mp_prev_enh; /*!< \brief mbelib previous frame (enhanced) */
+};
+
+/* From ambe.c */
+void ambe_decode_init(struct ambe_decoder *dec);
+void ambe_decode_fini(struct ambe_decoder *dec);
+
+int ambe_decode_frame(struct ambe_decoder *dec,
+ int16_t *audio, int N,
+ const uint8_t *frame, int bad);
+int ambe_decode_dtx(struct ambe_decoder *dec,
+ int16_t *audio, int N);
+
+/* From frame.c */
+void ambe_frame_unpack_raw(struct ambe_raw_params *rp, const uint8_t *frame);
+int ambe_frame_decode_params(struct ambe_subframe *sf,
+ struct ambe_subframe *sf_prev,
+ struct ambe_raw_params *rp);
+
+/* From math.c */
+float cosf_fast(float angle);
+void ambe_fdct(float *out, float *in, int N, int M);
+void ambe_idct(float *out, float *in, int N, int M);
+
+/* From tables.c */
+extern const uint8_t ambe_hpg_tbl[48][4];
+extern const float ambe_gain_tbl[256][2];
+extern const uint16_t ambe_v_uv_tbl[64];
+extern const float ambe_prba12_tbl[128][2];
+extern const float ambe_prba34_tbl[64][2];
+extern const float ambe_prba57_tbl[128][3];
+extern const float ambe_hoc0_tbl[128][4];
+extern const float ambe_hoc1_tbl[64][4];
+extern const float ambe_hoc2_tbl[64][4];
+extern const float ambe_hoc3_tbl[64][4];
+extern const float ambe_sf0_interp_tbl[4][2];
+extern const float ambe_sf0_perr14_tbl[64][4];
+extern const float ambe_sf0_perr58_tbl[32][4];
+
+/* From tone.c */
+int ambe_decode_tone(struct ambe_decoder *dec,
+ int16_t *audio, int N, const uint8_t *frame);
+
+
+/*! @} */
+
+#endif /* __OSMO_GMR1_CODEC_PRIVATE_H__ */
diff --git a/src/codec/tables.c b/src/codec/tables.c
new file mode 100644
index 0000000..a405cea
--- /dev/null
+++ b/src/codec/tables.c
@@ -0,0 +1,1134 @@
+/* GMR-1 AMBE vocoder - Tables */
+
+/* (C) 2013 by Sylvain Munaut <tnt@246tNt.com>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*! \addtogroup codec/private
+ * @{
+ */
+
+/*! \file codec/tables.c
+ * \brief Osmocom GMR-1 AMBE vocoder tables
+ */
+
+#include <stdint.h>
+
+/*! \brief Number of harmonics per group for a given L (starts at L=9) */
+const uint8_t ambe_hpg_tbl[48][4] = {
+ { 2, 2, 2, 3} /* L = 9 */,
+ { 2, 2, 3, 3},
+ { 2, 3, 3, 3},
+ { 2, 3, 3, 4},
+ { 3, 3, 3, 4},
+ { 3, 3, 4, 4},
+ { 3, 3, 4, 5},
+ { 3, 4, 4, 5},
+ { 3, 4, 5, 5},
+ { 4, 4, 5, 5},
+ { 4, 4, 5, 6},
+ { 4, 4, 6, 6},
+ { 4, 5, 6, 6},
+ { 4, 5, 6, 7},
+ { 5, 5, 6, 7},
+ { 5, 5, 7, 7},
+ { 5, 6, 7, 7},
+ { 5, 6, 7, 8},
+ { 5, 6, 8, 8},
+ { 6, 6, 8, 8},
+ { 6, 6, 8, 9},
+ { 6, 7, 8, 9},
+ { 6, 7, 9, 9},
+ { 6, 7, 9, 10},
+ { 7, 7, 9, 10},
+ { 7, 8, 9, 10},
+ { 7, 8, 10, 10},
+ { 7, 8, 10, 11},
+ { 8, 8, 10, 11},
+ { 8, 9, 10, 11},
+ { 8, 9, 11, 11},
+ { 8, 9, 11, 12},
+ { 8, 9, 11, 13},
+ { 8, 9, 12, 13},
+ { 8, 10, 12, 13},
+ { 9, 10, 12, 13},
+ { 9, 10, 12, 14},
+ { 9, 10, 13, 14},
+ { 9, 11, 13, 14},
+ { 10, 11, 13, 14},
+ { 10, 11, 13, 15},
+ { 10, 11, 14, 15},
+ { 10, 12, 14, 15},
+ { 10, 12, 14, 16},
+ { 11, 12, 14, 16},
+ { 11, 12, 15, 16},
+ { 11, 12, 15, 17},
+ { 11, 13, 15, 17}, /* L = 56 */
+};
+
+/* \brief Gain (subframe 0, subframe 1) */
+const float ambe_gain_tbl[256][2] = {
+ { -0.250000f, -0.250000f },
+ { +0.500000f, -0.500000f },
+ { +0.750000f, +0.750000f },
+ { +1.000000f, +0.000000f },
+ { +2.694336f, -1.780273f },
+ { +1.505859f, -0.089844f },
+ { +1.200195f, +0.719727f },
+ { +1.519531f, +0.910156f },
+ { +1.575195f, +1.520508f },
+ { +1.758789f, +1.686523f },
+ { +1.962891f, +1.791992f },
+ { +1.825195f, +1.992188f },
+ { +0.467773f, +1.686523f },
+ { +1.291016f, +1.441406f },
+ { +1.486328f, +1.935547f },
+ { +1.854492f, +2.328125f },
+ { +1.998047f, +0.444336f },
+ { +2.457031f, +0.266602f },
+ { +1.852539f, +0.899414f },
+ { +2.326172f, +0.845703f },
+ { +1.783203f, +1.342773f },
+ { +2.064453f, +1.244141f },
+ { +2.036133f, +1.547852f },
+ { +2.357422f, +1.338867f },
+ { +2.664062f, +1.724609f },
+ { +2.283203f, +1.666992f },
+ { +2.495117f, +1.903320f },
+ { +2.194336f, +1.882812f },
+ { +3.264648f, +0.294922f },
+ { +2.809570f, +1.036133f },
+ { +3.358398f, +1.009766f },
+ { +2.734375f, +1.429688f },
+ { +0.196289f, +3.059570f },
+ { +1.047852f, +2.736328f },
+ { +1.536133f, +2.499023f },
+ { +1.562500f, +3.231445f },
+ { +2.076172f, +2.083008f },
+ { +2.325195f, +2.013672f },
+ { +2.333008f, +2.181641f },
+ { +2.583008f, +2.100586f },
+ { +3.077148f, +1.631836f },
+ { +2.842773f, +1.973633f },
+ { +3.270508f, +1.856445f },
+ { +2.766602f, +2.154297f },
+ { +2.156250f, +2.318359f },
+ { +2.423828f, +2.339844f },
+ { +2.262695f, +2.541992f },
+ { +2.005859f, +2.839844f },
+ { +2.625977f, +2.315430f },
+ { +2.644531f, +2.464844f },
+ { +2.846680f, +2.389648f },
+ { +2.655273f, +2.627930f },
+ { +2.484375f, +2.551758f },
+ { +2.388672f, +2.776367f },
+ { +2.597656f, +2.848633f },
+ { +2.865234f, +2.641602f },
+ { +1.152344f, +3.904297f },
+ { +2.350586f, +3.088867f },
+ { +2.094727f, +3.514648f },
+ { +2.540039f, +3.231445f },
+ { +3.636719f, +1.640625f },
+ { +3.167969f, +2.131836f },
+ { +3.000000f, +2.323242f },
+ { +2.825195f, +2.525391f },
+ { +4.083984f, +1.436523f },
+ { +3.498047f, +2.150391f },
+ { +3.985352f, +1.961914f },
+ { +3.478516f, +2.397461f },
+ { +3.007812f, +2.522461f },
+ { +2.817383f, +2.783203f },
+ { +3.228516f, +2.431641f },
+ { +3.122070f, +2.636719f },
+ { +3.022461f, +2.736328f },
+ { +2.793945f, +2.946289f },
+ { +2.982422f, +2.849609f },
+ { +2.958984f, +3.000977f },
+ { +2.800781f, +3.152344f },
+ { +2.799805f, +3.389648f },
+ { +3.030273f, +3.177734f },
+ { +3.288086f, +3.029297f },
+ { +2.651367f, +3.675781f },
+ { +1.701172f, +4.336914f },
+ { +2.294922f, +3.939453f },
+ { +1.406250f, +5.000000f },
+ { +3.373047f, +2.619141f },
+ { +3.228516f, +2.765625f },
+ { +3.164062f, +2.910156f },
+ { +3.128906f, +3.040039f },
+ { +3.361328f, +2.868164f },
+ { +3.669922f, +2.584961f },
+ { +3.898438f, +2.388672f },
+ { +3.523438f, +2.802734f },
+ { +3.094727f, +3.301758f },
+ { +2.993164f, +3.511719f },
+ { +3.252930f, +3.336914f },
+ { +3.231445f, +3.168945f },
+ { +3.501953f, +3.005859f },
+ { +3.379883f, +3.152344f },
+ { +3.753906f, +2.853516f },
+ { +3.506836f, +3.168945f },
+ { +2.879883f, +4.072266f },
+ { +2.498047f, +4.471680f },
+ { +2.228516f, +5.155273f },
+ { +0.569336f, +6.061523f },
+ { +4.692383f, +1.986328f },
+ { +4.386719f, +2.451172f },
+ { +4.104492f, +2.850586f },
+ { +3.869141f, +3.131836f },
+ { +3.184570f, +3.526367f },
+ { +3.349609f, +3.495117f },
+ { +3.109375f, +3.801758f },
+ { +3.483398f, +3.559570f },
+ { +3.402344f, +3.304688f },
+ { +3.688477f, +3.081055f },
+ { +3.582031f, +3.269531f },
+ { +3.523438f, +3.406250f },
+ { +3.708008f, +3.312500f },
+ { +3.632812f, +3.520508f },
+ { +3.740234f, +3.449219f },
+ { +3.905273f, +3.368164f },
+ { +3.341797f, +3.716797f },
+ { +3.558594f, +3.694336f },
+ { +3.231445f, +4.089844f },
+ { +3.433594f, +3.908203f },
+ { +4.726562f, +2.729492f },
+ { +4.135742f, +3.233398f },
+ { +4.406250f, +3.089844f },
+ { +4.085938f, +3.517578f },
+ { +3.725586f, +3.644531f },
+ { +3.850586f, +3.572266f },
+ { +3.831055f, +3.752930f },
+ { +3.979492f, +3.644531f },
+ { +3.062500f, +4.463867f },
+ { +3.684570f, +3.842773f },
+ { +3.667969f, +4.026367f },
+ { +3.492188f, +4.209961f },
+ { +1.938477f, +5.909180f },
+ { +2.965820f, +4.902344f },
+ { +2.994141f, +5.447266f },
+ { +3.461914f, +5.069336f },
+ { +3.943359f, +3.811523f },
+ { +4.340820f, +3.446289f },
+ { +4.105469f, +3.754883f },
+ { +4.304688f, +3.649414f },
+ { +4.032227f, +3.921875f },
+ { +3.861328f, +3.956055f },
+ { +3.805664f, +4.154297f },
+ { +3.969727f, +4.078125f },
+ { +3.420898f, +4.545898f },
+ { +3.715820f, +4.432617f },
+ { +3.923828f, +4.300781f },
+ { +4.065430f, +4.208008f },
+ { +4.115234f, +4.025391f },
+ { +4.187500f, +3.890625f },
+ { +4.367188f, +3.826172f },
+ { +4.265625f, +4.010742f },
+ { +4.611328f, +3.655273f },
+ { +4.742188f, +3.284180f },
+ { +5.435547f, +2.901367f },
+ { +4.902344f, +3.943359f },
+ { +3.744141f, +4.716797f },
+ { +3.986328f, +4.517578f },
+ { +4.599609f, +3.930664f },
+ { +5.066406f, +3.545898f },
+ { +4.199219f, +4.132812f },
+ { +4.423828f, +4.046875f },
+ { +4.211914f, +4.260742f },
+ { +4.338867f, +4.162109f },
+ { +4.345703f, +4.291992f },
+ { +4.469727f, +4.196289f },
+ { +4.630859f, +4.108398f },
+ { +4.467773f, +4.321289f },
+ { +4.099609f, +4.374023f },
+ { +4.261719f, +4.399414f },
+ { +4.178711f, +4.560547f },
+ { +4.014648f, +4.748047f },
+ { +1.478516f, +7.333984f },
+ { +2.419922f, +6.616211f },
+ { +3.361328f, +6.083984f },
+ { +3.667969f, +5.605469f },
+ { +4.393555f, +4.422852f },
+ { +4.605469f, +4.262695f },
+ { +4.362305f, +4.538086f },
+ { +4.517578f, +4.436523f },
+ { +3.839844f, +5.159180f },
+ { +4.111328f, +5.006836f },
+ { +4.354492f, +4.989258f },
+ { +4.483398f, +4.814453f },
+ { +4.535156f, +4.541992f },
+ { +4.637695f, +4.434570f },
+ { +4.817383f, +4.365234f },
+ { +4.662109f, +4.547852f },
+ { +4.298828f, +4.725586f },
+ { +4.445312f, +4.653320f },
+ { +4.577148f, +4.662109f },
+ { +4.666992f, +4.790039f },
+ { +5.015625f, +4.486328f },
+ { +5.151367f, +4.260742f },
+ { +5.334961f, +3.931641f },
+ { +5.895508f, +3.884766f },
+ { +4.785156f, +4.228516f },
+ { +4.825195f, +4.518555f },
+ { +4.718750f, +4.651367f },
+ { +4.845703f, +4.656250f },
+ { +4.833008f, +4.784180f },
+ { +4.771484f, +4.909180f },
+ { +4.584961f, +4.994141f },
+ { +4.899414f, +4.937500f },
+ { +4.381836f, +5.285156f },
+ { +4.125977f, +5.541992f },
+ { +4.750000f, +5.098633f },
+ { +4.757812f, +5.340820f },
+ { +4.940430f, +5.166016f },
+ { +5.069336f, +4.881836f },
+ { +5.010742f, +5.030273f },
+ { +5.323242f, +4.840820f },
+ { +4.972656f, +4.762695f },
+ { +5.098633f, +4.670898f },
+ { +5.342773f, +4.547852f },
+ { +5.499023f, +4.323242f },
+ { +4.230469f, +6.020508f },
+ { +4.221680f, +6.533203f },
+ { +4.645508f, +5.621094f },
+ { +4.752930f, +5.988281f },
+ { +5.166016f, +5.011719f },
+ { +5.136719f, +5.173828f },
+ { +5.053711f, +5.355469f },
+ { +5.316406f, +5.132812f },
+ { +5.524414f, +5.062500f },
+ { +5.836914f, +4.714844f },
+ { +5.773438f, +5.334961f },
+ { +6.409180f, +4.941406f },
+ { +5.280273f, +5.305664f },
+ { +5.263672f, +5.515625f },
+ { +5.007812f, +5.597656f },
+ { +5.294922f, +5.808594f },
+ { +2.746094f, +8.125977f },
+ { +3.668945f, +7.252930f },
+ { +4.895508f, +6.830078f },
+ { +5.036133f, +6.223633f },
+ { +5.495117f, +5.355469f },
+ { +5.525391f, +5.579102f },
+ { +5.774414f, +5.652344f },
+ { +5.636719f, +5.845703f },
+ { +5.508789f, +6.226562f },
+ { +5.951172f, +5.958008f },
+ { +6.026367f, +6.290039f },
+ { +5.965820f, +6.783203f },
+ { +6.294922f, +5.596680f },
+ { +7.150391f, +5.895508f },
+ { +6.835938f, +6.656250f },
+ { +7.827148f, +7.060547f },
+ { +6.593750f, +7.486328f },
+ { +5.545898f, +7.523438f },
+ { +6.250977f, +8.595703f },
+ { +7.577148f, +8.196289f },
+};
+
+/*! \brief V/UV decisions (subframe 0 = low byte. MSBs = low freq) */
+const uint16_t ambe_v_uv_tbl[64] = {
+ 0x0000, 0xffff, 0xc0c0, 0xe0e0, 0xf0f0, 0x8080, 0xfefe, 0x0080,
+ 0xfcfc, 0x80c0, 0xf8f8, 0x8000, 0x00c0, 0xfffe, 0xfeff, 0xc000,
+ 0xf0e0, 0xc0e0, 0xfbfb, 0xfcfe, 0xf8f0, 0xfdfd, 0xfffb, 0xe000,
+ 0xe0f0, 0xfcff, 0xfdff, 0xe0c0, 0xfffc, 0xf0f8, 0xfefc, 0xfffd,
+ 0xf8fc, 0xfcf8, 0xfcfd, 0x4000, 0xf0c0, 0xf9f9, 0xfbff, 0xefef,
+ 0xf3f3, 0xc080, 0xf0e0, 0xfff8, 0xf0fc, 0xf1f1, 0x0040, 0xc0d0,
+ 0xc0f0, 0xf7f7, 0xfaf8, 0xfafa, 0xfcf0, 0xfef8, 0x00e0, 0x0100,
+ 0x1000, 0xe0e1, 0xe0f8, 0xf2f0, 0xf8ff, 0xfafe, 0xfff7, 0xdfdf,
+};
+
+/* \brief PRBA[1:2] */
+const float ambe_prba12_tbl[128][2] = {
+ { -0.042480f, +0.271484f },
+ { -0.082031f, +0.219727f },
+ { -0.579102f, +0.062988f },
+ { -0.708984f, +0.114746f },
+ { +0.277344f, +0.117676f },
+ { +0.254883f, +0.074707f },
+ { -0.012695f, -0.114258f },
+ { -0.069824f, -0.086914f },
+ { -0.416992f, +0.171387f },
+ { -0.502930f, +0.271484f },
+ { -0.884277f, -0.095703f },
+ { -1.116699f, -0.163574f },
+ { -0.106445f, +0.016602f },
+ { -0.168457f, +0.039062f },
+ { -0.341309f, -0.233398f },
+ { -0.450684f, -0.319824f },
+ { +0.094238f, +0.693848f },
+ { -0.014648f, +0.551758f },
+ { -0.008301f, +0.385742f },
+ { -0.109863f, +0.407715f },
+ { +0.467285f, +0.452148f },
+ { +0.358398f, +0.437012f },
+ { +0.174805f, +0.209473f },
+ { +0.150391f, +0.166992f },
+ { -0.273438f, +0.550781f },
+ { -0.449707f, +0.567871f },
+ { -0.829590f, +0.413574f },
+ { -1.075684f, +0.278320f },
+ { +0.103516f, +0.246094f },
+ { +0.063477f, +0.287109f },
+ { -0.171387f, +0.147949f },
+ { -0.252441f, +0.134766f },
+ { +0.204102f, +0.019043f },
+ { +0.175781f, -0.017578f },
+ { -0.077637f, -0.202148f },
+ { -0.160156f, -0.187988f },
+ { +0.602539f, -0.154297f },
+ { +0.534668f, -0.104980f },
+ { +0.256836f, -0.355957f },
+ { +0.154297f, -0.436523f },
+ { -0.178223f, -0.069824f },
+ { -0.257324f, -0.095215f },
+ { -0.726074f, -0.431641f },
+ { -0.867188f, -0.691406f },
+ { +0.190430f, -0.197754f },
+ { +0.136719f, -0.255371f },
+ { -0.173340f, -0.553711f },
+ { -0.392578f, -0.628418f },
+ { +0.321777f, +0.302246f },
+ { +0.277344f, +0.261230f },
+ { +0.115234f, +0.098145f },
+ { +0.068359f, +0.083008f },
+ { +1.054688f, +0.336914f },
+ { +0.906738f, +0.352539f },
+ { +0.413086f, +0.034180f },
+ { +0.368164f, +0.011719f },
+ { +0.065430f, +0.160645f },
+ { +0.020508f, +0.185547f },
+ { -0.308594f, +0.020020f },
+ { -0.388184f, -0.018555f },
+ { +0.355469f, +0.086426f },
+ { +0.318359f, +0.065430f },
+ { +0.114746f, -0.064453f },
+ { +0.064941f, -0.067383f },
+ { +0.292969f, +0.191406f },
+ { +0.243164f, +0.180664f },
+ { +0.023438f, +0.008301f },
+ { -0.015625f, -0.019043f },
+ { +0.728516f, +0.210938f },
+ { +0.659668f, +0.122070f },
+ { +0.339844f, -0.103516f },
+ { +0.331543f, -0.056152f },
+ { -0.018066f, +0.077148f },
+ { -0.058594f, +0.115723f },
+ { -0.502441f, -0.130371f },
+ { -0.628906f, -0.166504f },
+ { +0.285645f, +0.003418f },
+ { +0.252930f, -0.024902f },
+ { +0.096191f, -0.151367f },
+ { +0.045898f, -0.202637f },
+ { +0.625000f, +0.731445f },
+ { +0.407715f, +0.644531f },
+ { +0.228027f, +0.348145f },
+ { +0.180664f, +0.297852f },
+ { +1.320801f, +0.676270f },
+ { +1.041992f, +0.653809f },
+ { +0.565430f, +0.208008f },
+ { +0.488281f, +0.207031f },
+ { +0.166016f, +0.472168f },
+ { +0.112305f, +0.392578f },
+ { -0.203125f, +0.273438f },
+ { -0.295898f, +0.312012f },
+ { +0.487793f, +0.313965f },
+ { +0.413574f, +0.292969f },
+ { +0.198242f, +0.115723f },
+ { +0.184082f, +0.077637f },
+ { +0.577148f, +0.010254f },
+ { +0.505371f, +0.014648f },
+ { +0.325195f, -0.218750f },
+ { +0.287109f, -0.166504f },
+ { +1.284668f, -0.212402f },
+ { +1.041016f, -0.184082f },
+ { +0.804688f, -0.460449f },
+ { +0.680176f, -0.321777f },
+ { +0.239746f, -0.093750f },
+ { +0.191406f, -0.091797f },
+ { -0.043945f, -0.354492f },
+ { -0.177246f, -0.346191f },
+ { +0.455566f, -0.203125f },
+ { +0.473145f, -0.290039f },
+ { +0.396973f, -0.534668f },
+ { +0.155762f, -0.726074f },
+ { +0.699219f, +0.478516f },
+ { +0.643066f, +0.364746f },
+ { +0.500977f, +0.110840f },
+ { +0.437988f, +0.127441f },
+ { +1.643555f, +0.210938f },
+ { +1.371582f, +0.206543f },
+ { +0.811035f, -0.143555f },
+ { +0.718750f, -0.047852f },
+ { +0.382812f, +0.208008f },
+ { +0.357910f, +0.161621f },
+ { +0.130371f, +0.032715f },
+ { +0.093750f, +0.011230f },
+ { +1.021973f, +0.114258f },
+ { +0.864746f, +0.076172f },
+ { +0.428711f, -0.104492f },
+ { +0.425781f, -0.049316f },
+};
+
+/* \brief PRBA[3:4] */
+const float ambe_prba34_tbl[64][2] = {
+ { +0.439453f, +0.273438f },
+ { +0.307129f, +0.220215f },
+ { +0.338867f, +0.147949f },
+ { +0.253906f, +0.131836f },
+ { +0.557617f, +0.126953f },
+ { +0.386719f, +0.126465f },
+ { +0.408691f, +0.048828f },
+ { +0.298828f, +0.062500f },
+ { +0.344238f, -0.062012f },
+ { +0.259766f, -0.041016f },
+ { +0.258789f, -0.108398f },
+ { +0.194824f, -0.082520f },
+ { +0.456543f, -0.156738f },
+ { +0.312988f, -0.124512f },
+ { +0.318848f, -0.236328f },
+ { +0.220703f, -0.167969f },
+ { +0.171387f, +0.083008f },
+ { +0.113770f, +0.094727f },
+ { +0.111816f, +0.051270f },
+ { +0.060547f, +0.074707f },
+ { +0.188477f, +0.023926f },
+ { +0.138184f, +0.039551f },
+ { +0.135254f, -0.012207f },
+ { +0.086426f, +0.014160f },
+ { +0.082031f, -0.087891f },
+ { +0.009766f, -0.101562f },
+ { +0.036621f, -0.141113f },
+ { -0.057617f, -0.141602f },
+ { +0.099609f, -0.158691f },
+ { +0.011719f, -0.175781f },
+ { +0.067383f, -0.262207f },
+ { -0.056152f, -0.254395f },
+ { +0.182129f, +0.352539f },
+ { +0.044434f, +0.348633f },
+ { +0.120605f, +0.258789f },
+ { +0.036133f, +0.237305f },
+ { +0.180664f, +0.225586f },
+ { +0.088867f, +0.221191f },
+ { +0.130859f, +0.172852f },
+ { +0.059082f, +0.164062f },
+ { +0.012207f, +0.025879f },
+ { -0.026367f, +0.057617f },
+ { -0.041504f, +0.008301f },
+ { -0.084473f, +0.027832f },
+ { +0.021484f, -0.024414f },
+ { -0.021484f, +0.000000f },
+ { -0.031738f, -0.044434f },
+ { -0.082520f, -0.031738f },
+ { -0.068359f, +0.224121f },
+ { -0.163086f, +0.300781f },
+ { -0.152832f, +0.183594f },
+ { -0.283203f, +0.206543f },
+ { -0.034668f, +0.145508f },
+ { -0.102051f, +0.166992f },
+ { -0.099121f, +0.110840f },
+ { -0.179199f, +0.111328f },
+ { -0.181641f, -0.009277f },
+ { -0.288086f, +0.006836f },
+ { -0.241211f, -0.063965f },
+ { -0.434082f, -0.058105f },
+ { -0.164062f, -0.092285f },
+ { -0.271973f, -0.109375f },
+ { -0.203613f, -0.181152f },
+ { -0.333496f, -0.238770f },
+};
+
+/* \brief PRBA[5:7] */
+const float ambe_prba57_tbl[128][3] = {
+ { +0.012695f, -0.156250f, -0.120605f },
+ { -0.009277f, -0.090332f, -0.065918f },
+ { -0.062500f, -0.173340f, -0.151855f },
+ { -0.061035f, -0.105469f, -0.102051f },
+ { +0.079102f, -0.242676f, -0.139160f },
+ { +0.050781f, -0.146973f, -0.065918f },
+ { -0.039551f, -0.263672f, -0.182129f },
+ { -0.022949f, -0.181641f, -0.088379f },
+ { -0.033203f, -0.136719f, -0.044922f },
+ { -0.039062f, -0.071777f, -0.019043f },
+ { -0.084961f, -0.215820f, -0.066406f },
+ { -0.068359f, -0.129395f, -0.027832f },
+ { +0.020020f, -0.228027f, -0.042969f },
+ { +0.001953f, -0.132812f, -0.005859f },
+ { -0.052734f, -0.330566f, -0.035645f },
+ { -0.038086f, -0.213867f, +0.008301f },
+ { +0.192871f, -0.128906f, -0.024902f },
+ { +0.136719f, -0.054688f, +0.038574f },
+ { +0.111328f, -0.106934f, -0.008789f },
+ { +0.066895f, -0.054688f, +0.019531f },
+ { +0.255859f, -0.254883f, +0.000977f },
+ { +0.220215f, -0.125977f, +0.077148f },
+ { +0.133789f, -0.203613f, +0.004395f },
+ { +0.116211f, -0.105469f, +0.049316f },
+ { +0.143555f, -0.127441f, +0.070312f },
+ { +0.109375f, -0.051270f, +0.123047f },
+ { +0.067871f, -0.123535f, +0.059082f },
+ { +0.056641f, -0.055664f, +0.076172f },
+ { +0.175293f, -0.220215f, +0.117188f },
+ { +0.160156f, -0.116211f, +0.196777f },
+ { +0.074219f, -0.223145f, +0.091309f },
+ { +0.082031f, -0.122559f, +0.128906f },
+ { -0.172852f, -0.069336f, -0.072754f },
+ { -0.152344f, -0.026855f, +0.002930f },
+ { -0.268066f, -0.087891f, -0.121094f },
+ { -0.246094f, -0.022949f, -0.011230f },
+ { -0.175781f, -0.148926f, -0.092773f },
+ { -0.144043f, -0.090820f, -0.020996f },
+ { -0.303223f, -0.214355f, -0.161621f },
+ { -0.247070f, -0.124512f, -0.029785f },
+ { -0.212402f, -0.088867f, +0.005371f },
+ { -0.199707f, -0.001953f, +0.068848f },
+ { -0.338379f, -0.093262f, -0.021973f },
+ { -0.323730f, -0.006836f, +0.092773f },
+ { -0.186523f, -0.202148f, +0.004883f },
+ { -0.185059f, -0.101074f, +0.049316f },
+ { -0.303223f, -0.264160f, +0.009277f },
+ { -0.290527f, -0.139648f, +0.086426f },
+ { -0.033203f, -0.073730f, +0.076172f },
+ { -0.023438f, -0.025879f, +0.125000f },
+ { -0.095215f, -0.081543f, +0.071289f },
+ { -0.096680f, -0.020508f, +0.113770f },
+ { -0.025391f, -0.136719f, +0.108398f },
+ { -0.004395f, -0.078613f, +0.167969f },
+ { -0.094727f, -0.167969f, +0.101074f },
+ { -0.091797f, -0.093750f, +0.150879f },
+ { -0.049316f, -0.080078f, +0.143555f },
+ { -0.028320f, +0.005859f, +0.210449f },
+ { -0.142090f, -0.110840f, +0.149414f },
+ { -0.139648f, +0.005371f, +0.204102f },
+ { -0.020996f, -0.185547f, +0.189453f },
+ { -0.020020f, -0.087402f, +0.273926f },
+ { -0.124512f, -0.266113f, +0.179688f },
+ { -0.151855f, -0.124023f, +0.257812f },
+ { +0.153320f, +0.056641f, -0.220215f },
+ { +0.109863f, +0.121094f, -0.139160f },
+ { +0.038574f, +0.007324f, -0.212891f },
+ { +0.039062f, +0.062012f, -0.131836f },
+ { +0.208008f, -0.072754f, -0.209473f },
+ { +0.171875f, +0.010742f, -0.116699f },
+ { +0.077148f, -0.097168f, -0.245605f },
+ { +0.078613f, -0.015625f, -0.123535f },
+ { +0.098633f, +0.010742f, -0.134277f },
+ { +0.083496f, +0.059570f, -0.069336f },
+ { +0.010254f, -0.018066f, -0.134766f },
+ { +0.021973f, +0.028809f, -0.078125f },
+ { +0.128418f, -0.071289f, -0.119141f },
+ { +0.112793f, -0.009766f, -0.056152f },
+ { +0.054199f, -0.070312f, -0.132812f },
+ { +0.051758f, -0.022461f, -0.059570f },
+ { +0.295410f, +0.126953f, -0.076172f },
+ { +0.230957f, +0.245117f, +0.011230f },
+ { +0.184082f, +0.102539f, -0.039551f },
+ { +0.139648f, +0.199219f, -0.003418f },
+ { +0.329590f, -0.016113f, -0.005859f },
+ { +0.338379f, +0.108887f, +0.095703f },
+ { +0.212891f, +0.009277f, -0.000488f },
+ { +0.215820f, +0.087891f, +0.057617f },
+ { +0.202148f, +0.129883f, +0.047852f },
+ { +0.184570f, +0.232910f, +0.157227f },
+ { +0.138672f, +0.083008f, +0.021973f },
+ { +0.137207f, +0.145508f, +0.088379f },
+ { +0.241211f, +0.018066f, +0.099121f },
+ { +0.244629f, +0.101562f, +0.227539f },
+ { +0.149414f, +0.028320f, +0.074219f },
+ { +0.161621f, +0.065918f, +0.151855f },
+ { -0.058594f, +0.127930f, -0.189453f },
+ { -0.042480f, +0.219238f, -0.128418f },
+ { -0.152832f, +0.079102f, -0.203125f },
+ { -0.160156f, +0.169922f, -0.109375f },
+ { -0.063965f, +0.027832f, -0.131836f },
+ { -0.037598f, +0.109863f, -0.095703f },
+ { -0.132812f, -0.030762f, -0.219238f },
+ { -0.126953f, +0.062500f, -0.115723f },
+ { -0.095703f, +0.088379f, -0.087402f },
+ { -0.108887f, +0.182617f, -0.033203f },
+ { -0.198242f, +0.083496f, -0.091797f },
+ { -0.241211f, +0.182129f, -0.003906f },
+ { -0.077148f, +0.007324f, -0.062500f },
+ { -0.085449f, +0.081543f, -0.041016f },
+ { -0.134277f, +0.003906f, -0.103516f },
+ { -0.155762f, +0.080566f, -0.021484f },
+ { +0.024902f, +0.109863f, -0.007812f },
+ { +0.011719f, +0.178223f, +0.041992f },
+ { -0.029297f, +0.061035f, +0.004395f },
+ { -0.057129f, +0.124512f, +0.041504f },
+ { +0.045410f, +0.042969f, +0.017090f },
+ { +0.049805f, +0.100098f, +0.057617f },
+ { -0.004395f, +0.001953f, +0.008301f },
+ { -0.008789f, +0.056152f, +0.041992f },
+ { -0.011719f, +0.113770f, +0.062012f },
+ { -0.020020f, +0.237793f, +0.119141f },
+ { -0.083008f, +0.055176f, +0.051270f },
+ { -0.099121f, +0.133789f, +0.111328f },
+ { +0.024902f, +0.041504f, +0.084961f },
+ { +0.022461f, +0.121582f, +0.146484f },
+ { -0.040527f, +0.007812f, +0.048340f },
+ { -0.042480f, +0.068359f, +0.100586f },
+};
+
+/* \brief HOC for 1st frequency block */
+const float ambe_hoc0_tbl[128][4] = {
+ { +0.368652f, -0.230469f, -0.191406f, +0.158203f },
+ { +0.300781f, -0.079102f, -0.018066f, +0.124512f },
+ { +0.318848f, -0.202637f, +0.081055f, -0.000977f },
+ { +0.380371f, +0.044922f, +0.263184f, +0.108398f },
+ { +0.503418f, -0.068848f, -0.130371f, -0.029785f },
+ { +0.493652f, +0.189453f, -0.176758f, +0.151855f },
+ { +0.473145f, -0.065430f, +0.067383f, -0.150391f },
+ { +0.617188f, +0.196777f, +0.101074f, -0.020508f },
+ { +0.133301f, -0.141602f, -0.314453f, +0.069336f },
+ { +0.171875f, +0.024902f, -0.153809f, +0.085449f },
+ { +0.188477f, -0.050781f, -0.064941f, -0.079590f },
+ { +0.287598f, +0.139648f, +0.000000f, +0.042969f },
+ { +0.294922f, -0.118164f, -0.231445f, -0.161621f },
+ { +0.299805f, +0.123047f, -0.267090f, -0.032227f },
+ { +0.305176f, +0.091309f, -0.084473f, -0.280273f },
+ { +0.353027f, +0.357422f, -0.059082f, -0.093262f },
+ { +0.181641f, -0.402832f, -0.132812f, +0.117188f },
+ { +0.056641f, -0.196289f, -0.078613f, +0.199219f },
+ { +0.073242f, -0.285156f, +0.083984f, +0.112305f },
+ { +0.130371f, -0.092773f, +0.102051f, +0.252441f },
+ { +0.127930f, -0.209473f, +0.001953f, -0.077148f },
+ { +0.140137f, -0.115723f, -0.056152f, +0.062012f },
+ { +0.093262f, -0.223145f, +0.181641f, -0.052734f },
+ { +0.140137f, -0.081055f, +0.076660f, -0.004883f },
+ { +0.151855f, -0.540039f, -0.249512f, -0.097656f },
+ { +0.043457f, -0.258301f, -0.175781f, -0.067383f },
+ { -0.006836f, -0.333008f, +0.044922f, -0.077637f },
+ { -0.005371f, -0.128906f, +0.011719f, +0.031738f },
+ { -0.057617f, -0.366699f, -0.193848f, -0.279297f },
+ { +0.010742f, -0.143555f, -0.141113f, -0.193359f },
+ { +0.091309f, -0.168945f, +0.073730f, -0.280762f },
+ { +0.033203f, -0.056152f, +0.043457f, -0.147461f },
+ { +0.061035f, -0.031250f, -0.012695f, +0.002441f },
+ { +0.027344f, +0.083984f, +0.070801f, +0.087891f },
+ { +0.109863f, +0.031250f, +0.213379f, +0.060547f },
+ { +0.114746f, +0.263672f, +0.135254f, +0.241211f },
+ { +0.098633f, +0.059570f, +0.027344f, -0.082031f },
+ { +0.096191f, +0.186035f, +0.120605f, +0.023438f },
+ { +0.153320f, +0.126953f, +0.167969f, -0.131348f },
+ { +0.187500f, +0.382812f, +0.271973f, +0.023926f },
+ { -0.037109f, -0.004395f, -0.013672f, -0.053711f },
+ { -0.092285f, +0.080566f, -0.042969f, -0.004395f },
+ { -0.035645f, +0.056641f, +0.065430f, -0.040527f },
+ { -0.039551f, +0.233398f, +0.034180f, +0.030273f },
+ { -0.083496f, +0.086426f, -0.035156f, -0.126465f },
+ { -0.012207f, +0.125488f, -0.012207f, -0.067871f },
+ { +0.020020f, +0.161621f, +0.066406f, -0.288086f },
+ { +0.031738f, +0.359375f, +0.072754f, -0.100586f },
+ { -0.165039f, -0.411621f, +0.177734f, +0.067871f },
+ { -0.206543f, -0.182617f, +0.192383f, +0.162598f },
+ { -0.123047f, -0.277344f, +0.314453f, -0.124512f },
+ { -0.083008f, +0.016602f, +0.373047f, +0.057129f },
+ { -0.126953f, -0.173828f, +0.100586f, -0.009277f },
+ { -0.104492f, -0.090332f, +0.078125f, +0.043945f },
+ { -0.062500f, -0.104004f, +0.129395f, -0.098633f },
+ { -0.089355f, +0.000000f, +0.173340f, -0.002441f },
+ { -0.292969f, -0.209961f, +0.100098f, -0.048340f },
+ { -0.272461f, -0.037598f, +0.094238f, +0.042480f },
+ { -0.202637f, -0.133301f, +0.220215f, -0.114258f },
+ { -0.260742f, -0.022461f, +0.145508f, -0.096191f },
+ { -0.166992f, -0.216797f, +0.104980f, -0.225098f },
+ { -0.135254f, -0.033691f, +0.068359f, -0.055664f },
+ { -0.112305f, -0.006348f, +0.209473f, -0.226562f },
+ { -0.170410f, +0.009277f, +0.118164f, -0.137207f },
+ { +0.031738f, -0.041992f, -0.145020f, +0.123535f },
+ { -0.055176f, +0.095215f, -0.163086f, +0.234375f },
+ { -0.012695f, -0.008301f, -0.062012f, +0.044922f },
+ { +0.026855f, +0.073242f, -0.078613f, +0.127441f },
+ { +0.061035f, +0.071777f, -0.164062f, -0.074707f },
+ { +0.032715f, +0.158203f, -0.273926f, +0.091309f },
+ { +0.043457f, +0.069824f, -0.086426f, +0.019043f },
+ { +0.110352f, +0.188965f, -0.123047f, +0.001465f },
+ { -0.098633f, -0.028320f, -0.292480f, -0.001953f },
+ { -0.182129f, +0.115723f, -0.262207f, +0.152344f },
+ { -0.104492f, +0.087891f, -0.128418f, +0.059570f },
+ { -0.074219f, +0.251465f, -0.176270f, +0.064453f },
+ { +0.066406f, +0.044434f, -0.376465f, -0.171387f },
+ { -0.137207f, +0.248047f, -0.447266f, -0.061035f },
+ { -0.079102f, +0.166992f, -0.187500f, -0.085938f },
+ { +0.023926f, +0.445801f, -0.224121f, -0.011719f },
+ { -0.135254f, -0.413574f, -0.166016f, +0.082520f },
+ { -0.253906f, -0.163086f, -0.117188f, +0.361328f },
+ { -0.112793f, -0.232422f, -0.071289f, +0.090820f },
+ { -0.142090f, -0.087891f, -0.008789f, +0.218262f },
+ { -0.152344f, -0.179688f, -0.167480f, -0.075684f },
+ { -0.175293f, -0.068848f, -0.040527f, +0.104492f },
+ { -0.083496f, -0.076660f, +0.010742f, -0.019531f },
+ { -0.116211f, -0.021484f, -0.002930f, +0.035156f },
+ { -0.355469f, -0.489258f, -0.295410f, -0.100098f },
+ { -0.340332f, -0.144043f, -0.349121f, +0.018555f },
+ { -0.284180f, -0.334961f, -0.099121f, -0.101074f },
+ { -0.315918f, -0.142578f, -0.134277f, +0.039551f },
+ { -0.216797f, -0.330566f, -0.449219f, -0.278809f },
+ { -0.331543f, -0.104004f, -0.266113f, -0.172363f },
+ { -0.222168f, -0.113770f, -0.056641f, -0.235352f },
+ { -0.184082f, -0.051270f, -0.050293f, -0.050293f },
+ { -0.216797f, +0.050293f, -0.051758f, +0.013672f },
+ { -0.307129f, +0.110352f, -0.047852f, +0.108887f },
+ { -0.177734f, +0.058105f, +0.038574f, -0.020508f },
+ { -0.186523f, +0.168457f, +0.119629f, +0.154785f },
+ { -0.202637f, +0.151855f, -0.071289f, -0.025879f },
+ { -0.166504f, +0.268555f, -0.055176f, -0.051270f },
+ { -0.174316f, +0.195312f, +0.121582f, -0.076660f },
+ { -0.192871f, +0.410156f, +0.173340f, +0.062012f },
+ { -0.344238f, +0.020508f, -0.108887f, -0.073730f },
+ { -0.358398f, +0.202148f, -0.198242f, +0.062012f },
+ { -0.256836f, +0.097656f, +0.051270f, -0.108887f },
+ { -0.347656f, +0.192383f, +0.016602f, -0.018066f },
+ { -0.279297f, +0.163574f, -0.087891f, -0.258301f },
+ { -0.338379f, +0.336426f, -0.150391f, -0.093262f },
+ { -0.157227f, +0.295410f, -0.005371f, -0.210938f },
+ { -0.230469f, +0.612793f, -0.034668f, -0.157715f },
+ { -0.537109f, -0.526367f, -0.042969f, +0.113770f },
+ { -0.418945f, -0.219238f, -0.023926f, +0.166504f },
+ { -0.529785f, -0.210938f, +0.204102f, +0.054688f },
+ { -0.502441f, +0.004883f, +0.093750f, +0.241211f },
+ { -0.563477f, -0.197754f, -0.055176f, -0.049805f },
+ { -0.459473f, +0.037598f, +0.038086f, -0.033691f },
+ { -0.433594f, -0.070801f, +0.233887f, -0.039062f },
+ { -0.403320f, +0.151855f, +0.285156f, +0.062500f },
+ { -0.892090f, -0.333984f, -0.130371f, -0.081543f },
+ { -0.641113f, -0.040039f, -0.223145f, +0.060059f },
+ { -0.837891f, -0.131348f, +0.168945f, +0.107422f },
+ { -0.689453f, +0.212402f, -0.022949f, +0.026855f },
+ { -0.541504f, -0.253906f, -0.076172f, -0.286133f },
+ { -0.517578f, -0.001465f, -0.104492f, -0.234863f },
+ { -0.566406f, -0.024414f, +0.240723f, -0.166992f },
+ { -0.461914f, +0.264160f, +0.172363f, -0.184082f },
+};
+
+/* \brief HOC for 2nd frequency block */
+const float ambe_hoc1_tbl[64][4] = {
+ { -0.364258f, +0.365723f, +0.244141f, +0.045410f },
+ { -0.579102f, +0.200684f, -0.009766f, +0.049316f },
+ { -0.227051f, +0.341309f, -0.048828f, -0.008301f },
+ { -0.329102f, +0.122559f, -0.037598f, -0.017090f },
+ { -0.258301f, +0.068848f, +0.211426f, +0.120605f },
+ { -0.601074f, -0.050293f, +0.181641f, +0.054199f },
+ { -0.243652f, +0.145996f, +0.137207f, -0.101562f },
+ { -0.426270f, -0.007812f, +0.097168f, -0.137695f },
+ { +0.023926f, +0.219727f, +0.226074f, -0.005371f },
+ { -0.070801f, +0.079102f, +0.071289f, -0.009277f },
+ { +0.080566f, +0.355957f, +0.059570f, -0.162598f },
+ { +0.003906f, +0.132812f, +0.021484f, -0.132812f },
+ { -0.000488f, -0.001465f, +0.284180f, -0.035645f },
+ { -0.137207f, -0.091309f, +0.169434f, -0.136719f },
+ { +0.102539f, +0.044922f, +0.177734f, -0.221191f },
+ { -0.154785f, +0.020020f, +0.014160f, -0.318848f },
+ { -0.086426f, +0.261719f, +0.030762f, +0.185059f },
+ { -0.242676f, +0.156250f, -0.208008f, +0.111816f },
+ { +0.051758f, +0.322266f, -0.170898f, +0.121094f },
+ { -0.092285f, +0.228516f, -0.233398f, -0.122070f },
+ { +0.007324f, +0.097656f, +0.082520f, +0.166504f },
+ { -0.112305f, +0.073730f, -0.078613f, +0.075684f },
+ { +0.019531f, +0.155273f, -0.075684f, +0.012207f },
+ { -0.011719f, +0.042969f, -0.159180f, -0.062500f },
+ { +0.355469f, +0.314941f, +0.152832f, +0.054199f },
+ { +0.173340f, +0.168945f, -0.030273f, +0.022949f },
+ { +0.320312f, +0.309570f, -0.178711f, -0.014648f },
+ { +0.189941f, +0.147949f, -0.199707f, -0.141113f },
+ { +0.215332f, +0.123047f, +0.171387f, +0.117188f },
+ { +0.154297f, +0.027344f, +0.068359f, +0.029785f },
+ { +0.299805f, +0.122559f, +0.015625f, -0.117676f },
+ { +0.220703f, -0.037598f, -0.042969f, -0.210449f },
+ { -0.127441f, -0.118652f, +0.057617f, +0.198242f },
+ { -0.282227f, -0.165527f, -0.117676f, +0.165527f },
+ { -0.155273f, -0.030762f, -0.020996f, -0.026855f },
+ { -0.260742f, -0.062500f, -0.218750f, -0.112305f },
+ { -0.260742f, -0.344727f, +0.182129f, +0.091797f },
+ { -0.519043f, -0.346680f, -0.088867f, +0.025879f },
+ { -0.222168f, -0.140625f, +0.066895f, +0.032715f },
+ { -0.240234f, -0.235840f, -0.047363f, -0.126953f },
+ { +0.021973f, -0.033203f, +0.010742f, +0.057617f },
+ { -0.035645f, -0.162598f, +0.003418f, -0.014160f },
+ { +0.052734f, -0.026367f, +0.004883f, -0.048340f },
+ { +0.004883f, -0.104492f, -0.074707f, -0.147949f },
+ { +0.040527f, -0.177246f, +0.221680f, +0.105957f },
+ { -0.020508f, -0.354980f, +0.113770f, -0.000488f },
+ { +0.127441f, -0.160645f, +0.110840f, -0.043945f },
+ { +0.054688f, -0.319824f, +0.056152f, -0.223145f },
+ { +0.102051f, +0.036621f, -0.136719f, +0.276367f },
+ { -0.058105f, -0.117676f, -0.179199f, +0.076172f },
+ { +0.122559f, +0.030762f, -0.126953f, +0.084473f },
+ { +0.071777f, -0.081055f, -0.339355f, -0.026855f },
+ { +0.137695f, -0.191895f, +0.022461f, +0.213379f },
+ { -0.035156f, -0.339844f, -0.115234f, +0.175293f },
+ { +0.124512f, -0.161133f, -0.121582f, +0.054199f },
+ { -0.000977f, -0.270508f, -0.201172f, -0.075195f },
+ { +0.356934f, -0.011230f, -0.075195f, +0.129395f },
+ { +0.287598f, -0.123535f, -0.037598f, -0.047363f },
+ { +0.569336f, +0.065918f, -0.143555f, +0.021973f },
+ { +0.340820f, -0.035156f, -0.280762f, -0.009277f },
+ { +0.378906f, -0.094238f, +0.183594f, -0.002930f },
+ { +0.308105f, -0.334473f, +0.076172f, +0.063477f },
+ { +0.587891f, -0.206055f, +0.034668f, +0.000977f },
+ { +0.332520f, -0.322754f, -0.201172f, -0.001465f },
+};
+
+/* \brief HOC for 3rd frequency block */
+const float ambe_hoc2_tbl[64][4] = {
+ { -0.107422f, +0.202637f, +0.255859f, -0.011719f },
+ { -0.214844f, -0.538086f, -0.206543f, +0.003418f },
+ { -0.027832f, -0.366211f, -0.125488f, +0.198730f },
+ { +0.109375f, -0.022461f, +0.040039f, -0.047852f },
+ { -0.603516f, -0.089844f, +0.060059f, +0.119629f },
+ { +0.167480f, -0.050781f, -0.051270f, +0.058594f },
+ { -0.235352f, -0.060059f, -0.284180f, +0.049805f },
+ { +0.449219f, -0.298828f, -0.132324f, -0.052734f },
+ { +0.189941f, -0.092285f, -0.009277f, +0.264648f },
+ { -0.048828f, +0.046387f, -0.372559f, -0.064941f },
+ { +0.484375f, +0.374023f, +0.152344f, -0.004395f },
+ { +0.045410f, -0.102539f, +0.215820f, +0.086914f },
+ { -0.036133f, +0.066895f, +0.014648f, -0.071289f },
+ { -0.209961f, +0.056152f, +0.125488f, -0.217773f },
+ { +0.041992f, +0.019043f, +0.048828f, +0.265137f },
+ { -0.182129f, +0.083984f, -0.065430f, +0.020996f },
+ { -0.022949f, -0.003418f, -0.002930f, +0.066895f },
+ { -0.396484f, +0.604492f, -0.018555f, -0.075684f },
+ { -0.437988f, -0.310547f, -0.026855f, +0.006836f },
+ { -0.156738f, +0.153320f, -0.177734f, -0.184082f },
+ { +0.028809f, +0.010742f, -0.126953f, -0.048340f },
+ { +0.111328f, +0.125488f, +0.041504f, +0.038574f },
+ { -0.100586f, +0.170410f, +0.048340f, +0.182129f },
+ { -0.133301f, -0.140137f, -0.099609f, +0.027344f },
+ { +0.587891f, -0.200684f, +0.144531f, +0.144043f },
+ { -0.081543f, +0.023926f, +0.148926f, +0.001465f },
+ { +0.227051f, -0.032227f, +0.150391f, +0.036133f },
+ { -0.266602f, -0.096191f, +0.338867f, -0.118164f },
+ { +0.357422f, -0.079102f, -0.019531f, +0.098145f },
+ { -0.059082f, +0.314453f, +0.041992f, -0.142578f },
+ { -0.124023f, +0.358887f, -0.032715f, +0.105469f },
+ { +0.006348f, -0.163574f, -0.011719f, -0.043457f },
+ { -0.362305f, +0.057129f, +0.021484f, +0.104980f },
+ { -0.263184f, -0.176270f, +0.031738f, +0.164551f },
+ { +0.124512f, +0.143555f, +0.284180f, +0.124512f },
+ { +0.164551f, -0.268555f, -0.051270f, +0.056152f },
+ { -0.062012f, +0.035156f, -0.174316f, +0.189941f },
+ { +0.413574f, +0.090332f, -0.321777f, -0.175293f },
+ { -0.005371f, -0.098633f, +0.035156f, -0.225586f },
+ { -0.347656f, -0.123047f, -0.103516f, -0.166504f },
+ { -0.021973f, +0.187988f, -0.074707f, +0.003906f },
+ { +0.109375f, +0.112305f, -0.050293f, -0.279297f },
+ { +0.183105f, +0.375488f, -0.160156f, -0.106445f },
+ { -0.210938f, -0.065430f, +0.076172f, -0.016113f },
+ { +0.116699f, -0.221191f, -0.288574f, -0.043945f },
+ { -0.092773f, -0.245605f, -0.222656f, -0.220215f },
+ { +0.183105f, +0.332520f, +0.093262f, +0.028809f },
+ { -0.301758f, +0.245117f, +0.083496f, -0.078125f },
+ { +0.253418f, +0.088379f, -0.116211f, -0.001953f },
+ { +0.442383f, -0.003418f, +0.195312f, -0.007812f },
+ { +0.220703f, -0.336426f, +0.158691f, -0.011719f },
+ { -0.311035f, +0.226562f, -0.162109f, +0.028809f },
+ { -0.541016f, +0.119141f, +0.203125f, -0.046387f },
+ { +0.080566f, +0.074219f, +0.226562f, -0.167969f },
+ { +0.281738f, -0.106445f, -0.126953f, -0.123047f },
+ { -0.213379f, -0.111328f, +0.261230f, +0.187500f },
+ { -0.010742f, -0.242676f, +0.092285f, +0.127441f },
+ { +0.166504f, -0.171875f, +0.140625f, -0.141602f },
+ { +0.302246f, +0.090820f, +0.070801f, -0.118164f },
+ { +0.257812f, +0.179688f, -0.015625f, +0.187012f },
+ { +0.548340f, +0.153809f, -0.108398f, -0.020508f },
+ { -0.093262f, -0.379395f, +0.070312f, -0.080078f },
+ { +0.236328f, +0.011719f, -0.321289f, +0.164062f },
+ { +0.104492f, +0.204590f, -0.219238f, +0.086914f },
+};
+
+/* \brief HOC for last frequency block */
+const float ambe_hoc3_tbl[64][4] = {
+ { +0.168457f, +0.110352f, +0.166504f, -0.110840f },
+ { +0.338379f, +0.063965f, +0.101074f, +0.089844f },
+ { +0.256836f, -0.126465f, +0.064941f, -0.130371f },
+ { +0.408691f, -0.185547f, -0.034180f, +0.050781f },
+ { +0.114258f, +0.246582f, -0.041992f, -0.150879f },
+ { +0.395996f, +0.225586f, -0.069336f, -0.021973f },
+ { +0.150879f, -0.011719f, -0.199707f, -0.177734f },
+ { +0.257812f, +0.024414f, -0.229004f, +0.114258f },
+ { -0.027832f, -0.088867f, +0.277832f, -0.020020f },
+ { +0.104492f, -0.083496f, +0.072266f, +0.071777f },
+ { -0.129395f, -0.252930f, +0.079590f, -0.026855f },
+ { +0.073730f, -0.316406f, -0.042969f, +0.115723f },
+ { -0.029297f, -0.039551f, +0.025879f, -0.170898f },
+ { +0.093750f, +0.014160f, -0.037598f, -0.006348f },
+ { -0.190918f, -0.177246f, -0.153809f, -0.147461f },
+ { -0.033203f, -0.144531f, -0.168457f, +0.036133f },
+ { -0.096191f, +0.198242f, +0.156250f, +0.006348f },
+ { +0.113770f, +0.264160f, +0.106934f, +0.123047f },
+ { -0.062500f, +0.043457f, +0.015137f, +0.023438f },
+ { +0.010254f, +0.083496f, -0.049805f, +0.229980f },
+ { -0.226074f, +0.414062f, +0.004395f, -0.054199f },
+ { +0.035645f, +0.371094f, -0.165039f, +0.094727f },
+ { -0.137207f, +0.166504f, -0.085449f, -0.091309f },
+ { -0.058594f, +0.130859f, -0.217285f, +0.048340f },
+ { -0.296875f, +0.042480f, +0.116699f, -0.131348f },
+ { -0.204590f, +0.000488f, +0.152344f, +0.177734f },
+ { -0.495605f, -0.143066f, +0.133789f, +0.004395f },
+ { -0.298828f, -0.233887f, -0.041016f, +0.205078f },
+ { -0.548828f, +0.221191f, +0.065430f, +0.030273f },
+ { -0.257812f, +0.170410f, -0.021484f, +0.109863f },
+ { -0.424316f, +0.047852f, -0.164062f, +0.008301f },
+ { -0.226562f, -0.054199f, -0.056641f, +0.061523f },
+ { +0.000000f, -2.388672f, +0.000000f, -2.138672f },
+ { +0.000000f, -2.013672f, +0.000000f, -1.888672f },
+ { +0.000000f, +0.000000f, +0.334961f, +0.334961f },
+ { +0.665039f, +0.665039f, +1.000000f, +1.000000f },
+ { +1.225098f, +1.225098f, +1.465820f, +1.079590f },
+ { +1.676270f, +1.337402f, +1.780273f, +1.127441f },
+ { +1.450195f, +1.450195f, +1.649902f, +1.649902f },
+ { +1.850098f, +1.850098f, +2.049805f, +1.673340f },
+ { +1.395020f, +1.629883f, +1.756836f, +2.109863f },
+ { +1.799316f, +2.498535f, +2.039551f, +2.101074f },
+ { +2.191895f, +2.130859f, +2.202637f, +2.261719f },
+ { +2.370117f, +2.280762f, +2.432617f, +2.474609f },
+ { +2.104980f, +2.435059f, +1.996094f, +2.682129f },
+ { +2.223633f, +2.595215f, +2.170410f, +2.867676f },
+ { +2.138672f, +1.921387f, +2.373535f, +2.008789f },
+ { +2.457031f, +1.873047f, +2.549805f, +2.189941f },
+ { +2.389648f, +2.715332f, +2.370605f, +2.928223f },
+ { +2.570312f, +2.886230f, +2.679688f, +3.064941f },
+ { +0.299805f, +0.799805f, +0.483887f, +1.406250f },
+ { +0.446289f, +2.411133f, +0.918457f, +1.759277f },
+ { +1.305664f, +2.787598f, +1.577637f, +2.526855f },
+ { +1.667969f, +2.817871f, +1.482910f, +2.258301f },
+ { +0.966797f, +2.099121f, +0.885254f, +2.812988f },
+ { +1.198242f, +2.594727f, +1.218262f, +3.094238f },
+ { +2.020020f, +3.117676f, +2.213379f, +3.314453f },
+ { +2.476074f, +3.186523f, +2.285156f, +3.489746f },
+ { +1.679688f, +3.270996f, +1.525391f, +3.752930f },
+ { +1.190430f, +3.576172f, +1.341797f, +4.195801f },
+ { +0.269531f, +3.548828f, +0.729004f, +3.265625f },
+ { +0.982910f, +3.903320f, +0.971680f, +4.340332f },
+ { +1.841309f, +3.510742f, +1.849121f, +4.137207f },
+ { +1.952637f, +3.729004f, +2.333496f, +3.879395f },
+};
+
+/* \brief Interpolation ratios for subframe 0 magnitude prediction */
+const float ambe_sf0_interp_tbl[4][2] = {
+ { +0.90f, +0.10f },
+ { +0.70f, +0.30f },
+ { +0.50f, +0.50f },
+ { +0.17f, +0.83f },
+};
+
+/* \brief Prediction Error [1:4] for subframe 0 */
+const float ambe_sf0_perr14_tbl[64][4] = {
+ { -0.106445f, +0.011230f, -0.166992f, -0.022461f },
+ { -0.056641f, +0.166504f, -0.139648f, -0.102051f },
+ { -0.004883f, +0.052246f, -0.106934f, +0.084961f },
+ { +0.031250f, +0.188477f, -0.142578f, +0.077148f },
+ { -0.089355f, -0.052246f, -0.041016f, -0.159180f },
+ { -0.043945f, +0.056152f, -0.008301f, -0.088379f },
+ { -0.001953f, +0.006348f, -0.062012f, -0.007324f },
+ { -0.060059f, +0.075684f, -0.046387f, +0.006348f },
+ { -0.340332f, -0.018555f, -0.109863f, +0.066895f },
+ { -0.197754f, +0.207520f, -0.016113f, +0.043457f },
+ { -0.138672f, -0.012695f, -0.009766f, +0.166992f },
+ { -0.083008f, +0.154297f, +0.046875f, +0.236816f },
+ { -0.465332f, -0.145020f, +0.042480f, -0.085938f },
+ { -0.201172f, +0.037598f, +0.015137f, -0.050293f },
+ { -0.211914f, -0.160156f, +0.062500f, +0.029785f },
+ { -0.292969f, +0.076172f, +0.160156f, +0.107910f },
+ { +0.110840f, +0.004883f, -0.197754f, -0.041504f },
+ { +0.135742f, +0.063965f, -0.063477f, +0.041016f },
+ { +0.184570f, +0.004395f, -0.186523f, +0.133789f },
+ { +0.144043f, +0.087891f, -0.006348f, +0.194336f },
+ { +0.043945f, -0.115723f, -0.107422f, -0.091797f },
+ { +0.095215f, -0.048340f, -0.037598f, +0.004883f },
+ { +0.108398f, -0.133789f, -0.107910f, +0.060059f },
+ { +0.085449f, -0.027832f, -0.033203f, +0.095215f },
+ { -0.079590f, -0.103516f, -0.095703f, +0.035156f },
+ { -0.003906f, -0.009277f, +0.000977f, +0.024902f },
+ { -0.001953f, -0.091309f, -0.061035f, +0.164551f },
+ { +0.002441f, +0.032715f, +0.020020f, +0.109863f },
+ { -0.158691f, -0.269531f, -0.145996f, -0.108887f },
+ { -0.060547f, -0.063965f, +0.024902f, +0.010742f },
+ { -0.067383f, -0.315918f, -0.055176f, +0.086426f },
+ { +0.007812f, -0.086426f, +0.082520f, +0.125488f },
+ { +0.065430f, +0.081543f, -0.076172f, -0.069824f },
+ { +0.112305f, +0.234375f, -0.011719f, -0.095215f },
+ { +0.035645f, +0.092285f, -0.001465f, +0.006348f },
+ { +0.099609f, +0.224609f, +0.073242f, +0.075195f },
+ { +0.080078f, +0.014648f, +0.022949f, -0.147461f },
+ { +0.103516f, +0.095215f, +0.136230f, -0.152344f },
+ { +0.053223f, +0.017578f, +0.009277f, -0.038574f },
+ { +0.111816f, +0.073730f, +0.125488f, +0.003906f },
+ { -0.020996f, +0.013184f, +0.068848f, -0.052734f },
+ { -0.047852f, +0.137695f, +0.079590f, -0.054199f },
+ { -0.075195f, +0.050781f, +0.046875f, +0.030762f },
+ { -0.008301f, +0.155273f, +0.186523f, +0.063477f },
+ { -0.093750f, -0.066406f, +0.119629f, -0.083008f },
+ { -0.101562f, +0.080078f, +0.179688f, -0.135254f },
+ { -0.076172f, -0.001465f, +0.160156f, +0.064941f },
+ { -0.078613f, -0.005859f, +0.341309f, +0.011230f },
+ { +0.291016f, +0.043945f, -0.125488f, -0.176270f },
+ { +0.203613f, +0.027832f, +0.007324f, -0.041016f },
+ { +0.312500f, -0.001953f, -0.063965f, +0.053711f },
+ { +0.380371f, +0.174316f, +0.078125f, +0.021973f },
+ { +0.175293f, -0.284180f, -0.069824f, -0.177246f },
+ { +0.192871f, -0.101562f, +0.063965f, -0.082520f },
+ { +0.282227f, -0.250977f, +0.011719f, +0.054199f },
+ { +0.394043f, -0.064453f, +0.111816f, -0.040527f },
+ { +0.039062f, -0.067871f, +0.031738f, -0.043457f },
+ { +0.040527f, -0.026367f, +0.070801f, +0.014648f },
+ { +0.117188f, -0.115723f, +0.039062f, +0.036133f },
+ { +0.145508f, +0.000000f, +0.072754f, +0.079590f },
+ { +0.027832f, -0.163574f, +0.114746f, -0.115234f },
+ { +0.062500f, -0.047852f, +0.152832f, -0.059082f },
+ { +0.027344f, -0.190430f, +0.152344f, +0.042480f },
+ { +0.178223f, -0.077148f, +0.190918f, +0.095215f },
+};
+
+/* \brief Prediction Error [5:8] for subframe 0 */
+const float ambe_sf0_perr58_tbl[32][4] = {
+ { -0.006836f, +0.065430f, +0.135254f, +0.032715f },
+ { -0.019531f, +0.053223f, +0.054688f, -0.052734f },
+ { -0.143066f, +0.037598f, +0.059082f, +0.054688f },
+ { -0.104004f, +0.000000f, +0.097168f, -0.123047f },
+ { -0.003906f, -0.020996f, +0.027832f, +0.066895f },
+ { -0.026367f, -0.023926f, +0.021973f, -0.013672f },
+ { -0.067383f, -0.093262f, +0.105469f, +0.100586f },
+ { -0.109863f, -0.104980f, +0.027832f, -0.027832f },
+ { +0.137207f, +0.000000f, +0.125488f, +0.075684f },
+ { +0.092773f, +0.020508f, +0.126953f, -0.112305f },
+ { +0.043945f, -0.060547f, +0.069824f, -0.016113f },
+ { +0.020996f, -0.105957f, +0.146484f, -0.070312f },
+ { +0.191406f, -0.145508f, +0.053711f, +0.034668f },
+ { +0.141113f, -0.080566f, +0.025391f, -0.080078f },
+ { +0.056152f, -0.142578f, +0.020996f, +0.047363f },
+ { +0.000488f, -0.165527f, +0.020996f, -0.149902f },
+ { +0.020996f, +0.133301f, +0.024902f, +0.095215f },
+ { -0.061523f, +0.183594f, -0.054688f, -0.006836f },
+ { -0.021973f, +0.042969f, -0.031738f, +0.020020f },
+ { -0.090332f, +0.081543f, -0.018066f, -0.071777f },
+ { -0.032227f, +0.068359f, -0.101074f, +0.124023f },
+ { +0.017090f, +0.067383f, -0.151855f, -0.009766f },
+ { -0.060059f, -0.056152f, -0.078613f, +0.083496f },
+ { -0.148438f, +0.006836f, -0.104980f, -0.041016f },
+ { +0.171387f, +0.106445f, -0.006836f, +0.029785f },
+ { +0.111328f, +0.072754f, -0.046387f, -0.137695f },
+ { +0.058594f, +0.019531f, +0.007324f, -0.016602f },
+ { +0.007812f, -0.005371f, -0.022461f, -0.098145f },
+ { +0.105957f, -0.038086f, -0.065430f, +0.114258f },
+ { +0.124512f, -0.021484f, -0.109863f, -0.014160f },
+ { +0.041504f, -0.032227f, -0.036133f, +0.019043f },
+ { -0.015137f, -0.137207f, -0.127930f, -0.061035f },
+};
+
+/*! @} */
diff --git a/src/codec/tone.c b/src/codec/tone.c
new file mode 100644
index 0000000..e958706
--- /dev/null
+++ b/src/codec/tone.c
@@ -0,0 +1,210 @@
+/* GMR-1 AMBE vocoder - Tone frames */
+
+/* (C) 2013 by Sylvain Munaut <tnt@246tNt.com>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*! \addtogroup codec/private
+ * @{
+ */
+
+/*! \file codec/tone.c
+ * \brief Osmocom GMR-1 AMBE vocoder tone frames handling
+ */
+
+#include <errno.h>
+#include <math.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "private.h"
+
+
+/*! \brief Structure describing a dual-frequency tone */
+struct tone_desc {
+ char *name;
+ int f1;
+ int f2;
+};
+
+/*! \brief DTMF tones descriptions */
+static const struct tone_desc dtmf_tones[] = {
+ { "1", 1209, 697 },
+ { "4", 1209, 770 },
+ { "7", 1209, 852 },
+ { "*", 1209, 941 },
+ { "2", 1336, 697 },
+ { "5", 1336, 770 },
+ { "8", 1336, 852 },
+ { "0", 1336, 941 },
+ { "3", 1477, 697 },
+ { "6", 1477, 770 },
+ { "9", 1477, 852 },
+ { "#", 1477, 941 },
+ { "A", 1633, 697 },
+ { "B", 1633, 770 },
+ { "C", 1633, 852 },
+ { "D", 1633, 941 },
+};
+
+/*! \brief KNOX tones descriptions */
+static const struct tone_desc knox_tones[] = {
+ { "1", 1052, 606 },
+ { "4", 1052, 672 },
+ { "7", 1052, 743 },
+ { "*", 1052, 820 },
+ { "2", 1162, 606 },
+ { "5", 1162, 672 },
+ { "8", 1162, 743 },
+ { "0", 1162, 820 },
+ { "3", 1297, 606 },
+ { "6", 1297, 672 },
+ { "9", 1297, 743 },
+ { "#", 1297, 820 },
+ { "A", 1430, 606 },
+ { "B", 1430, 672 },
+ { "C", 1430, 743 },
+ { "D", 1430, 820 },
+};
+
+/*! \brief Call progress tones descriptions */
+static const struct tone_desc call_progress_tones[] = {
+ { "Dial", 440, 350 },
+ { "Ring", 480, 440 },
+ { "Busy", 630, 480 },
+ { "????", 490, 350 },
+};
+
+
+/*! \brief Synthesize and add a tone to a given audio buffer
+ * \param[out] audio Audio buffer to mix the tone into
+ * \param[in] N number of audio samples to generate
+ * \param[in] ampl Tone amplitude
+ * \param[in] freq_hz Tone frequency in Hertz
+ * \param[inout] phase_p Pointer to phase variable to use
+ */
+static void
+tone_gen(int16_t *audio, int N, int ampl, int freq_hz, float *phase_p)
+{
+ float phase, phase_step;
+ int i;
+
+ phase = *phase_p;
+ phase_step = (2.0f * M_PI * freq_hz) / AMBE_RATE;
+
+ for (i=0; i<N; i++)
+ {
+ audio[i] += (int16_t)(ampl * cosf(phase));
+ phase += phase_step;
+ }
+
+ *phase_p = phase;
+}
+
+
+/*! \brief Decodes an AMBE tone frame
+ * \param[in] dec AMBE decoder state
+ * \param[out] audio Output audio buffer
+ * \param[in] N number of audio samples to produce (152..168)
+ * \param[in] frame Frame data (10 bytes = 80 bits). Must be tone frame !
+ * \returns 0 for success. -EINVAL if frame was invalid.
+ */
+int
+ambe_decode_tone(struct ambe_decoder *dec,
+ int16_t *audio, int N, const uint8_t *frame)
+{
+ int p_sf_sel, p_log_ampl, p_freq;
+ int i, j, cnt;
+ int start, stop;
+ int amplitude;
+
+ /* Decode parameters */
+ p_sf_sel = frame[0] & 3;
+ p_log_ampl = frame[1];
+
+ p_freq = 0;
+ for (i=0; i<8; i++) {
+ cnt = 0;
+ for (j=0; j<8; j++)
+ cnt += (frame[j] >> (7-i)) & 1;
+ p_freq = (p_freq << 1) | (cnt >= 4);
+ }
+
+ /* Clear audio */
+ memset(audio, 0x00, sizeof(int16_t) * N);
+
+ /* Audio start / stop */
+ start = (p_sf_sel & 2) ? 0 : N << 1;
+ stop = (p_sf_sel & 1) ? ((N << 1) - 1) : (N - 1);
+
+ if (start < stop)
+ return 0;
+
+ /* Compute amplitude */
+ amplitude = (int)(32767.0f * exp2f(((float)p_log_ampl-255.0f)/17.0f));
+
+ /* Interpret frequency code */
+ if (p_freq == 0xff)
+ {
+ /* Inactive, nothing to do */
+ }
+ else if ((p_freq >= 0xa0) && (p_freq <= 0xa3))
+ {
+ /* Call progress tone */
+ int cpi = p_freq & 0xf;
+
+ tone_gen(&audio[start], stop-start+1, amplitude >> 1,
+ call_progress_tones[cpi].f1, &dec->tone_phase_f1);
+ tone_gen(&audio[start], stop-start+1, amplitude >> 1,
+ call_progress_tones[cpi].f2, &dec->tone_phase_f2);
+ }
+ else if ((p_freq >= 0x90) && (p_freq <= 0x9f))
+ {
+ /* Call progress tone */
+ int ki = p_freq & 0xf;
+
+ tone_gen(&audio[start], stop-start+1, amplitude >> 1,
+ knox_tones[ki].f1, &dec->tone_phase_f1);
+ tone_gen(&audio[start], stop-start+1, amplitude >> 1,
+ knox_tones[ki].f2, &dec->tone_phase_f2);
+ }
+ else if ((p_freq >= 0x80) && (p_freq <= 0x8f))
+ {
+ /* Call progress tone */
+ int di = p_freq & 0xf;
+
+ tone_gen(&audio[start], stop-start+1, amplitude >> 1,
+ dtmf_tones[di].f1, &dec->tone_phase_f1);
+ tone_gen(&audio[start], stop-start+1, amplitude >> 1,
+ dtmf_tones[di].f2, &dec->tone_phase_f2);
+ }
+ else if (p_freq < 0x7f)
+ {
+ int freq_hz = (p_freq * 125) >> 2; /* 31.25 Hz increments */
+
+ tone_gen(&audio[start], stop-start+1, amplitude,
+ freq_hz, &dec->tone_phase_f1);
+ }
+ else
+ {
+ /* Invalid */
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*! @} */
diff --git a/src/gmr1_ambe_decode.c b/src/gmr1_ambe_decode.c
new file mode 100644
index 0000000..5f61ac0
--- /dev/null
+++ b/src/gmr1_ambe_decode.c
@@ -0,0 +1,195 @@
+/* GMR-1 Codec decoder tool */
+
+/* (C) 2013 by Sylvain Munaut <tnt@246tNt.com>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <osmocom/gmr1/codec/codec.h>
+
+
+static const uint8_t wav_hdr[] = {
+ /* WAV header */
+ 'R', 'I', 'F', 'F', /* ChunkID */
+ 0x00, 0x00, 0x00, 0x00, /* ChunkSize */
+ 'W', 'A', 'V', 'E', /* Format */
+
+ /* Sub chunk: format */
+ 'f', 'm', 't', ' ', /* Subchunk1ID */
+ 0x10, 0x00, 0x00, 0x00, /* Subchunk1Size */
+ 0x01, 0x00, /* AudioFormat: PCM */
+ 0x01, 0x00, /* NumChannels: Mono */
+ 0x40, 0x1f, 0x00, 0x00, /* SampleRate: 8000 Hz */
+ 0x80, 0x3e, 0x00, 0x00, /* ByteRate: 16k/s */
+ 0x02, 0x00, /* BlockAlign: 2 bytes */
+ 0x10, 0x00, /* BitsPerSample: 16 */
+
+ /* Sub chunk: data */
+ 'd', 'a', 't', 'a', /* Subchunk2ID */
+ 0x00, 0x00, 0x00, 0x00, /* Subchunk2Size */
+};
+
+static uint32_t
+le32(uint32_t v)
+{
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ return v;
+#else
+ return ((v & 0x000000ff) << 24) |
+ ((v & 0x0000ff00) << 8) |
+ ((v & 0x00ff0000) >> 8) |
+ ((v & 0xff000000) >> 24);
+#endif
+}
+
+static uint16_t
+le16(uint16_t v)
+{
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ return v;
+#else
+ return ((v & 0x00ff) << 8) |
+ ((v & 0xff00) >> 8);
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+ struct gmr1_codec *codec = NULL;
+ FILE *fin, *fout;
+ int is_wave = 0, l, rv;
+
+ /* Arguments */
+ if (argc > 3) {
+ fprintf(stderr, "Usage: %s [in_file [out_file]]\n", argv[0]);
+ return -1;
+ }
+
+ if ((argc < 2) || !strcmp(argv[1], "-"))
+ fin = stdin;
+ else {
+ fin = fopen(argv[1], "rb");
+ if (!fin) {
+ fprintf(stderr, "[!] Unable to open input file\n");
+ return -1;
+ }
+ }
+
+ if ((argc < 3) || !strcmp(argv[2], "-"))
+ fout = stdout;
+ else {
+ fout = fopen(argv[2], "wb");
+ if (!fout) {
+ fprintf(stderr, "[!] Unable to open output file\n");
+ return -1;
+ }
+
+ l = strlen(argv[2]);
+
+ if ((l > 4) && (!strcmp(".wav", &argv[2][l-4])))
+ is_wave = 1;
+ }
+
+ /* Write inital wave header */
+ if (is_wave) {
+ rv = fwrite(wav_hdr, sizeof(wav_hdr), 1, fout);
+ if (rv != 1) {
+ fprintf(stderr, "[!] Failed to write WAV header\n");
+ goto exit;
+ }
+ }
+
+ /* Init decoder */
+ codec = gmr1_codec_alloc();
+ if (!codec)
+ goto exit;
+
+ /* Process all frames */
+ l = 0;
+
+ while (!feof(fin))
+ {
+ uint8_t frame[10];
+ int16_t audio[160];
+ int rv, i;
+
+ /* Read input frame */
+ rv = fread(frame, 1, 10, fin);
+ if (rv != 10)
+ break;
+
+ /* Decompress */
+ rv = gmr1_codec_decode_frame(codec, audio, 160, frame, 0);
+ if (rv) {
+ fprintf(stderr, "[!] codec error\n");
+ break;
+ }
+
+ /* Write audio output */
+ for (i=0; i<160; i++)
+ audio[i] = le16(audio[i]);
+
+ rv = fwrite(audio, 2, 160, fout);
+ if (rv != 160) {
+ fprintf(stderr, "[!] short write\n");
+ break;
+ }
+
+ /* Keep track of number of samples */
+ l += 160;
+ }
+
+ /* Release decoder */
+ gmr1_codec_release(codec);
+
+ /* Fix wave header */
+ if (is_wave)
+ {
+ uint32_t v;
+
+ /* Fixup Subchunk2Size */
+ v = le32(l * 2);
+
+ rv = fseek(fout, 40, SEEK_SET);
+ if (rv < 0)
+ goto exit;
+
+ rv = fwrite(&v, 4, 1, fout);
+ if (rv < 0)
+ goto exit;
+
+ /* Fixup ChunkSize */
+ v = le32(l * 2 + 36);
+
+ rv = fseek(fout, 4, SEEK_SET);
+ if (rv < 0)
+ goto exit;
+
+ rv = fwrite(&v, 4, 1, fout);
+ if (rv < 0)
+ goto exit;
+ }
+
+exit:
+ /* Close in/out */
+ fclose(fout);
+ fclose(fin);
+
+ /* All done ! */
+ return 0;
+}