aboutsummaryrefslogtreecommitdiffstats
path: root/src/codec/ambe.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/codec/ambe.c')
-rw-r--r--src/codec/ambe.c140
1 files changed, 140 insertions, 0 deletions
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;
+}
+
+/*! @} */