osmo-gmr/src/codec/ambe.c

151 lines
3.3 KiB
C

/* 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_prev);
}
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 void
ambe_subframe_to_mbelib(mbe_parms *mp, struct ambe_subframe *sf)
{
float unvc;
int i;
mp->w0 = sf->f0 * (2.0f * (float)M_PI);
mp->L = sf->L;
unvc = 0.2046f / sqrtf(mp->w0); /* ??? */
for (i=1; i<=mp->L; i++) {
int j = (int)((i-1) * 16.0f * sf->f0);
mp->Vl[i] = sf->v_uv[j];
mp->Ml[i] = powf(2.0, sf->Mlog[i-1]) / 6.0f;
if (!mp->Vl[i])
mp->Ml[i] *= unvc;
}
}
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];
mbe_parms mp[2];
/* Unpack frame */
ambe_frame_unpack_raw(&rp, frame);
/* Decode subframe parameters */
ambe_frame_decode_params(sf, &dec->sf_prev, &rp);
/* Convert both subframes to mbelib's format */
ambe_subframe_to_mbelib(&mp[0], &sf[0]);
ambe_subframe_to_mbelib(&mp[1], &sf[1]);
/* Synthesize speech (using mbelib for now) */
mbe_spectralAmpEnhance(&mp[0]);
mbe_spectralAmpEnhance(&mp[1]);
mbe_synthesizeSpeech(audio, &mp[0], &dec->mp_prev, 2);
mbe_synthesizeSpeech(audio+80, &mp[1], &mp[0], 2);
mbe_moveMbeParms(&mp[1], &dec->mp_prev);
/* 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:
return ambe_decode_tone(dec, audio, N, frame);
}
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;
}
/*! @} */