osmo-gmr/src/codec/tone.c

211 lines
5.2 KiB
C

/* GMR-1 AMBE vocoder - Tone frames */
/* (C) 2011-2019 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; /*!< \brief Tone description */
int f1; /*!< \brief Frequency 1 (Hz) */
int f2; /*!< \brief Frequency 2 (Hz) */
};
/*! \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_PIf * 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) : ((N >> 1) - 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))
{
/* Knox 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))
{
/* DTMF 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;
}
/*! @} */