1
0
Fork 0

codec: Import current codec code

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
This commit is contained in:
Sylvain Munaut 2015-12-23 20:53:29 +01:00
parent 30e476ab5f
commit 39141a86bb
12 changed files with 4256 additions and 0 deletions

12
codec/Makefile Normal file
View File

@ -0,0 +1,12 @@
CC=gcc
CFLAGS=`pkg-config libosmocore --cflags` -Wall -O2 -march=native
LDLIBS=`pkg-config libosmocore --libs` -lm
OBJS=ir77_ambe_decode
all: $(OBJS)
ir77_ambe_decode: ir77_ambe_decode.o ambe.o ecc.o frame.o math.o synth.o tables.o tone.o
clean:
rm -f *.o $(OBJS)

176
codec/ambe.c Normal file
View File

@ -0,0 +1,176 @@
/* Iridium AMBE vocoder - AMBE API */
/* (C) 2015 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
* @{
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "ambe.h"
#include "private.h"
/*! \brief Allocates and inits a decoder object
* \returns A newly allocated and initialized decoder
*/
struct ir77_ambe_decoder *
ir77_ambe_decode_alloc(void)
{
struct ir77_ambe_decoder *dec;
dec = calloc(1, sizeof(struct ir77_ambe_decoder));
if (!dec)
return NULL;
ir77_ambe_synth_init(&dec->synth);
dec->sf_prev.w0 = 0.09378;
dec->sf_prev.f0 = dec->sf_prev.w0 / (2 * M_PIf);
dec->sf_prev.L = 30;
return dec;
}
/*! \brief Release a decoder object created by \ref ir77_ambe_decode_alloc
* \param[in] dec Decoder object
*/
void
ir77_ambe_decode_release(struct ir77_ambe_decoder *dec)
{
free(dec);
}
/*! \brief Decodes an AMBE frame to audio
* \param[in] dec Decoder object
* \param[out] audio Output audio buffers
* \param[in] N number of audio samples to produce (== 360 for now)
* \param[in] frame Frame data (as de-prioritized 103 ubits), Must be speech !
* \returns 0 for success. Negative error code otherwise.
*/
static int
ir77_ambe_decode_speech(struct ir77_ambe_decoder *dec,
int16_t *audio, int N, const ubit_t *frame_lin)
{
struct ir77_ambe_raw_params rp;
struct ir77_ambe_subframe sf[2];
/* Read out params */
ir77_ambe_frame_unpack_raw(&rp, frame_lin);
/* Decode params */
ir77_ambe_frame_decode_params(sf, &dec->sf_prev, &rp);
/* Expand them */
ir77_ambe_subframe_expand(&sf[0]);
ir77_ambe_subframe_expand(&sf[1]);
/* Perform the actual audio synthesis */
ir77_ambe_synth_enhance(&dec->synth, &sf[0]);
ir77_ambe_synth_enhance(&dec->synth, &sf[1]);
ir77_ambe_synth_audio(&dec->synth, audio , &sf[0], &dec->sf_prev);
ir77_ambe_synth_audio(&dec->synth, audio + 180, &sf[1], &sf[0]);
/* Save previous subframe */
memcpy(&dec->sf_prev, &sf[1], sizeof(struct ir77_ambe_subframe));
return 0;
}
/*! \brief Decodes an AMBE superframe to audio
* \param[in] dec Decoder object
* \param[out] audio Output audio buffers
* \param[in] N number of audio samples to produce (== 720 for now)
* \param[in] superframe SuperFrame data (39 bytes = 312 bits)
* \returns 0 for success. Negative error code otherwise.
*/
int
ir77_ambe_decode_superframe(struct ir77_ambe_decoder *dec,
int16_t *audio, int N,
const uint8_t *superframe)
{
ubit_t superframe_bits[312];
ubit_t frame_bits[156];
int i;
/* Unpack to ubits */
osmo_pbit2ubit_ext(superframe_bits, 0, superframe, 0, 312, 1);
/* Process each frame */
for (i=0; i<2; i++)
{
ubit_t frame[103], frame_lin[103];
enum ir77_ambe_frame_type type;
int err[6];
uint32_t seed;
/* De-interleave */
ir77_ambe_interleave(frame_bits, superframe_bits+i, 2, 156, 1);
/* De-FEC */
err[0] = ir77_ambe_golay24_decode(&frame[ 0], &frame_bits[ 0], &seed);
ir77_ambe_scramble(&frame_bits[24], &frame_bits[24], 156-24-33, seed);
err[1] = ir77_ambe_golay23_decode (&frame[12], &frame_bits[ 24], NULL);
err[2] = ir77_ambe_golay23_decode (&frame[24], &frame_bits[ 47], NULL);
err[3] = ir77_ambe_golay23_decode (&frame[36], &frame_bits[ 70], NULL);
err[4] = ir77_ambe_hamming1511_decode(&frame[48], &frame_bits[ 93]);
err[5] = ir77_ambe_hamming1511_decode(&frame[59], &frame_bits[108]);
memcpy(&frame[70], &frame_bits[123], 33);
/* Skip bad frames */
if ((err[1] + err[2] + err[3]) > 6) {
memset(&audio[360*i], 0x0, sizeof(int16_t) * 360);
continue;
}
/* De-prioritize */
ir77_ambe_prioritize(frame_lin, frame, 1);
/* Classify frame */
type = ir77_ambe_frame_classify(frame_lin);
/* Decode appropriately */
switch (type)
{
case AMBE_SPEECH:
ir77_ambe_decode_speech(dec, &audio[360*i], 360, frame_lin);
break;
case AMBE_TONE:
ir77_ambe_decode_tone(dec, &audio[360*i], 360, frame_lin);
break;
case AMBE_SILENCE:
case AMBE_INVALID:
memset(&audio[360*i], 0x0, sizeof(int16_t) * 360);
break;
}
}
return 0;
}
/*! @} */

44
codec/ambe.h Normal file
View File

@ -0,0 +1,44 @@
/* Iridium AMBE vocoder - AMBE API */
/* (C) 2015 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_IR77_AMBE_AMBE_H__
#define __OSMO_IR77_AMBE_AMBE_H__
/*! \defgroup codec AMBE vocoder
* \ingroup codec
* @{
*/
/*! \file codec/ambe.h
* \brief Iridium AMBE vocoder header
*/
#include <stdint.h>
struct ir77_ambe_decoder;
struct ir77_ambe_decoder *ir77_ambe_decode_alloc(void);
void ir77_ambe_decode_release(struct ir77_ambe_decoder *dec);
int ir77_ambe_decode_superframe(struct ir77_ambe_decoder *dec,
int16_t *audio, int N,
const uint8_t *superframe);
/*! @} */
#endif /* __OSMO_IR77_AMBE_AMBE_H__ */

270
codec/ecc.c Normal file
View File

@ -0,0 +1,270 @@
/* Iridium AMBE vocoder - ECC routines */
/* (C) 2015 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/ecc.c
* \brief Iridium AMBE vocoder ECC routines
*/
#include <osmocom/core/bits.h>
#include "ecc_tables.h"
/* Local helpers ---------------------------------------------------------- */
/*! \brief Writes a given word as ubits (MSBs first)
* \param[out] bits Pointer where to write the ubits
* \param[in] word Word to write
* \param[in] N Number of bits
*/
static void
_ubit_write(ubit_t *bits, uint32_t word, int N)
{
int i, s;
s = N - 1;
for (i=0; i<N; i++)
bits[i] = (word >> s--) & 1;
}
/*! \brief Reads a word from ubits (MSBs first)
* \param[in] bits Pointer where to read the ubits from
* \param[in] N Number of bits
* \returns The reconstructed value (unsigned)
*/
static uint32_t
_ubit_read(ubit_t *bits, int N)
{
uint32_t rv = 0;
int i;
for (i=0; i<N; i++)
rv = (rv << 1) | bits[i];
return rv;
}
/*! \brief Computed the hamming weight of a given word (number of 1 bits)
* \param[in] v Value
* \returns Hamming weight of 'v'
*/
static int
_weight(uint32_t v)
{
const int hw[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
int i, t;
t = 0;
for (i=0; i<32; i+=4)
t += hw[(v >> i) & 0xf];
return t;
}
/* Golay 23/12 & 24/12 ---------------------------------------------------- */
/*! \brief Computes Golay Syndrome of given word
* \param[in] data Data word
* \param[in] tbl Mask table to use
* \returns Syndrome of 'data' using 'tbl'
*/
static uint32_t
_golay_syndrome(uint32_t data, const uint32_t *tbl)
{
uint32_t syndrome, mask;
int i;
syndrome = 0;
mask = 1<<11;
for (i=0; i<12; i++) {
if (data & mask)
syndrome ^= tbl[i];
mask >>= 1;
}
return syndrome;
}
/*! \brief Encode one word using Golay 23/12
* \param[out] out 23 ubits output buffer
* \param[in] in 12 ubits input buffer
*/
void
ir77_ambe_golay23_encode(ubit_t *out, ubit_t *in)
{
uint32_t cw;
cw = _ubit_read(in, 12);
cw = (cw << 11) | _golay_syndrome(cw, _golay23_syn_tbl);
_ubit_write(out, cw, 23);
}
/*! \brief Decode one word using Golay 23/12 code
* \param[out] out 12 ubits output buffer
* \param[in] in 23 ubits input buffer
* \param[out] data_p Optional return pointer for the decoded word
* \returns Number of bits errors
*/
int
ir77_ambe_golay23_decode(ubit_t *out, ubit_t *in, uint32_t *data_p)
{
uint32_t cw, data, ecc_rx, ecc_ex, syn;
int w = 0;
cw = _ubit_read(in, 23);
data = cw >> 11;
ecc_rx = cw & 0x7ff;
ecc_ex = _golay_syndrome(data, _golay23_syn_tbl);
syn = ecc_ex ^ ecc_rx;
if (syn) {
uint32_t errors = _golay23_dec_tbl[syn];
data ^= errors >> 11;
w = _weight(errors);
}
_ubit_write(out, data, 12);
if (data_p)
*data_p = data;
return w;
}
/*! \brief Encode one word using Golay 24/12
* \param[out] out 24 ubits output buffer
* \param[in] in 12 ubits input buffer
*/
void
ir77_ambe_golay24_encode(ubit_t *out, ubit_t *in)
{
uint32_t cw;
cw = _ubit_read(in, 12);
cw = (cw << 12) | _golay_syndrome(cw, _golay24_syn_tbl);
_ubit_write(out, cw, 24);
}
/*! \brief Decode one word using Golay 24/12 code
* \param[out] out 12 ubits output buffer
* \param[in] in 24 ubits input buffer
* \param[out] data_p Optional return pointer for the decoded word
* \returns Number of bits errors
*/
int
ir77_ambe_golay24_decode(ubit_t *out, ubit_t *in, uint32_t *data_p)
{
uint32_t cw, data, ecc_rx, ecc_ex, syn;
int w = 0;
cw = _ubit_read(in, 24);
data = cw >> 12;
ecc_rx = cw & 0xfff;
ecc_ex = _golay_syndrome(data, _golay24_syn_tbl);
syn = ecc_ex ^ ecc_rx;
if (syn) {
uint32_t errors = _golay23_dec_tbl[syn >> 1];
data ^= errors >> 11;
w = _weight(errors);
//w += (syn & 1) ^ (w & 1); /* FIXME */
}
_ubit_write(out, data, 12);
if (data_p)
*data_p = data;
return w;
}
/* Hamming 15/11 codes ---------------------------------------------------- */
/*! \brief Computes Hamming 15/11 syndrome of a given value
* \param[in] v Value
* \returns Hamming 15/11 syndrome of 'v'
*/
static uint32_t
_hamming1511_syndrome(uint32_t v)
{
uint32_t s = 0;
int i;
for (i=0; i<4; i++) {
s <<= 1;
s |= _weight(v & _ham1511_mask_tbl[i]) & 1;
}
return s;
}
/*! \brief Encode one word using Hamming 15/11
* \param[out] out 15 ubits output buffer
* \param[in] in 11 ubits input buffer
*/
void
ir77_ambe_hamming1511_encode(ubit_t *out, ubit_t *in)
{
uint32_t cw;
cw = _ubit_read(in, 11) << 4;
cw |= _hamming1511_syndrome(cw);
_ubit_write(out, cw, 15);
}
/*! \brief Decode one word using Hamming 15/11
* \param[out] out 11 ubits output buffer
* \param[in] in 15 ubits input buffer
* \returns 0 if no errors, 1 if errors
*/
int
ir77_ambe_hamming1511_decode(ubit_t *out, ubit_t *in)
{
uint32_t cw = _ubit_read(in, 15);
uint32_t syndrome;
int w = 0;
syndrome = _hamming1511_syndrome(cw);
if (syndrome) {
cw ^= 1 << _ham1511_fix_tbl[syndrome];
w = 1;
}
_ubit_write(out, cw >> 4, 11);
return w;
}
/*! @} */

571
codec/ecc_tables.h Normal file
View File

@ -0,0 +1,571 @@
/* Iridium AMBE vocoder - ECC tables */
/* (C) 2015 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_IR77_AMBE_ECC_TABLES_H__
#define __OSMO_IR77_AMBE_ECC_TABLES_H__
/*! \addtogroup codec_private
* @{
*/
/*! \file codec/ecc_tables.h
* \brief Iridium AMBE vocoder ECC tables
*/
/*! \brief Golay 23,12 - syndrome table */
static const uint32_t _golay23_syn_tbl[] = {
0x63a, 0x31d, 0x7b4, 0x3da, 0x1ed, 0x6cc,
0x366, 0x1b3, 0x6e3, 0x54b, 0x49f, 0x475,
};
/*! \brief Golay 24,12 - syndrome table */
static const uint32_t _golay24_syn_tbl[] = {
0xc75, 0x63b, 0xf68, 0x7b4, 0x3da, 0xd99,
0x6cd, 0x367, 0xdc6, 0xa97, 0x93e, 0x8eb,
};
/*! \brief Golay 23,12 - Decoding table (idx=syndrome, value=error_mask) */
static const uint32_t _golay23_dec_tbl[] = {
0x000000, 0x000001, 0x000002, 0x000003,
0x000004, 0x000005, 0x000006, 0x000007,
0x000008, 0x000009, 0x00000a, 0x00000b,
0x00000c, 0x00000d, 0x00000e, 0x024020,
0x000010, 0x000011, 0x000012, 0x000013,
0x000014, 0x000015, 0x000016, 0x412000,
0x000018, 0x000019, 0x00001a, 0x180800,
0x00001c, 0x200300, 0x048040, 0x001480,
0x000020, 0x000021, 0x000022, 0x000023,
0x000024, 0x000025, 0x000026, 0x024008,
0x000028, 0x000029, 0x00002a, 0x024004,
0x00002c, 0x024002, 0x024001, 0x024000,
0x000030, 0x000031, 0x000032, 0x008180,
0x000034, 0x000c40, 0x301000, 0x0c0200,
0x000038, 0x043000, 0x400600, 0x210040,
0x090080, 0x508000, 0x002900, 0x024010,
0x000040, 0x000041, 0x000042, 0x000043,
0x000044, 0x000045, 0x000046, 0x280080,
0x000048, 0x000049, 0x00004a, 0x002500,
0x00004c, 0x111000, 0x048010, 0x400a00,
0x000050, 0x000051, 0x000052, 0x021200,
0x000054, 0x000c20, 0x048008, 0x104100,
0x000058, 0x404080, 0x048004, 0x210020,
0x048002, 0x0a2000, 0x048000, 0x048001,
0x000060, 0x000061, 0x000062, 0x540000,
0x000064, 0x000c10, 0x010300, 0x00b000,
0x000068, 0x088200, 0x001880, 0x210010,
0x602000, 0x040180, 0x180400, 0x024040,
0x000070, 0x000c04, 0x086000, 0x210008,
0x000c01, 0x000c00, 0x420080, 0x000c02,
0x120100, 0x210002, 0x210001, 0x210000,
0x005200, 0x000c08, 0x048020, 0x210004,
0x000080, 0x000081, 0x000082, 0x000083,
0x000084, 0x000085, 0x000086, 0x280040,
0x000088, 0x000089, 0x00008a, 0x050200,
0x00008c, 0x00a800, 0x500100, 0x001410,
0x000090, 0x000091, 0x000092, 0x008120,
0x000094, 0x160000, 0x004a00, 0x001408,
0x000098, 0x404040, 0x222000, 0x001404,
0x090020, 0x001402, 0x001401, 0x001400,
0x0000a0, 0x0000a1, 0x0000a2, 0x008110,
0x0000a4, 0x401200, 0x042400, 0x110800,
0x0000a8, 0x300400, 0x001840, 0x482000,
0x090010, 0x040140, 0x208200, 0x024080,
0x0000b0, 0x008102, 0x008101, 0x008100,
0x090008, 0x206000, 0x420040, 0x008104,
0x090004, 0x020a00, 0x144000, 0x008108,
0x090000, 0x090001, 0x090002, 0x001420,
0x0000c0, 0x0000c1, 0x0000c2, 0x280004,
0x0000c4, 0x280002, 0x280001, 0x280000,
0x0000c8, 0x404010, 0x001820, 0x128000,
0x020600, 0x040120, 0x016000, 0x280008,
0x0000d0, 0x404008, 0x110400, 0x042800,
0x003100, 0x018200, 0x420020, 0x280010,
0x404001, 0x404000, 0x080300, 0x404002,
0x300800, 0x404004, 0x048080, 0x001440,
0x0000e0, 0x032000, 0x001808, 0x004600,
0x10c000, 0x040108, 0x420010, 0x280020,
0x001802, 0x040104, 0x001800, 0x001801,
0x040101, 0x040100, 0x001804, 0x040102,
0x240200, 0x181000, 0x420004, 0x008140,
0x420002, 0x000c80, 0x420000, 0x420001,
0x00a400, 0x404020, 0x001810, 0x210080,
0x090040, 0x040110, 0x420008, 0x102200,
0x000100, 0x000101, 0x000102, 0x000103,
0x000104, 0x000105, 0x000106, 0x041800,
0x000108, 0x000109, 0x00010a, 0x002440,
0x00010c, 0x200210, 0x500080, 0x098000,
0x000110, 0x000111, 0x000112, 0x0080a0,
0x000114, 0x200208, 0x0a0400, 0x104040,
0x000118, 0x200204, 0x015000, 0x460000,
0x200201, 0x200200, 0x002820, 0x200202,
0x000120, 0x000121, 0x000122, 0x008090,
0x000124, 0x182000, 0x010240, 0x600400,
0x000128, 0x410800, 0x2c0000, 0x101200,
0x009400, 0x0400c0, 0x002810, 0x024100,
0x000130, 0x008082, 0x008081, 0x008080,
0x444000, 0x031000, 0x002808, 0x008084,
0x120040, 0x084400, 0x002804, 0x008088,
0x002802, 0x200220, 0x002800, 0x002801,
0x000140, 0x000141, 0x000142, 0x002408,
0x000144, 0x428000, 0x010220, 0x104010,
0x000148, 0x002402, 0x002401, 0x002400,
0x084800, 0x0400a0, 0x221000, 0x002404,
0x000150, 0x0d0000, 0x600800, 0x104004,
0x003080, 0x104002, 0x104001, 0x104000,
0x120020, 0x009800, 0x080280, 0x002410,
0x410400, 0x200240, 0x048100, 0x104008,
0x000160, 0x205000, 0x010204, 0x0a0800,
0x010202, 0x040088, 0x010200, 0x010201,
0x120010, 0x040084, 0x40c000, 0x002420,
0x040081, 0x040080, 0x010208, 0x040082,
0x120008, 0x402200, 0x041400, 0x0080c0,
0x288000, 0x000d00, 0x010210, 0x104020,
0x120000, 0x120001, 0x120002, 0x210100,
0x120004, 0x040090, 0x002840, 0x481000,
0x000180, 0x000181, 0x000182, 0x008030,
0x000184, 0x014400, 0x500008, 0x022200,
0x000188, 0x0a1000, 0x500004, 0x204800,
0x500002, 0x040060, 0x500000, 0x500001,
0x000190, 0x008022, 0x008021, 0x008020,
0x003040, 0x480800, 0x250000, 0x008024,
0x040c00, 0x112000, 0x080240, 0x008028,
0x02c000, 0x200280, 0x500010, 0x001500,
0x0001a0, 0x008012, 0x008011, 0x008010,
0x220800, 0x040048, 0x085000, 0x008014,
0x006200, 0x040044, 0x030400, 0x008018,
0x040041, 0x040040, 0x500020, 0x040042,
0x008003, 0x008002, 0x008001, 0x008000,
0x100600, 0x008006, 0x008005, 0x008004,
0x601000, 0x00800a, 0x008009, 0x008008,
0x090100, 0x040050, 0x002880, 0x00800c,
0x0001c0, 0x100a00, 0x064000, 0x411000,
0x003010, 0x040028, 0x008c00, 0x280100,
0x218000, 0x040024, 0x080210, 0x002480,
0x040021, 0x040020, 0x500040, 0x040022,
0x003004, 0x220400, 0x080208, 0x008060,
0x003000, 0x003001, 0x003002, 0x104080,
0x080202, 0x404100, 0x080200, 0x080201,
0x003008, 0x040030, 0x080204, 0x030800,
0x480400, 0x04000c, 0x302000, 0x008050,
0x040009, 0x040008, 0x010280, 0x04000a,
0x040005, 0x040004, 0x001900, 0x040006,
0x040001, 0x040000, 0x040003, 0x040002,
0x014800, 0x008042, 0x008041, 0x008040,
0x003020, 0x040018, 0x420100, 0x008044,
0x120080, 0x040014, 0x080220, 0x008048,
0x040011, 0x040010, 0x204400, 0x040012,
0x000200, 0x000201, 0x000202, 0x000203,
0x000204, 0x000205, 0x000206, 0x108400,
0x000208, 0x000209, 0x00020a, 0x050080,
0x00020c, 0x200110, 0x083000, 0x400840,
0x000210, 0x000211, 0x000212, 0x021040,
0x000214, 0x200108, 0x004880, 0x0c0020,
0x000218, 0x200104, 0x400420, 0x00e000,
0x200101, 0x200100, 0x130000, 0x200102,
0x000220, 0x000221, 0x000222, 0x202800,
0x000224, 0x401080, 0x010140, 0x0c0010,
0x000228, 0x088040, 0x400410, 0x101100,
0x140800, 0x012400, 0x208080, 0x024200,
0x000230, 0x114000, 0x400408, 0x0c0004,
0x02a000, 0x0c0002, 0x0c0001, 0x0c0000,
0x400402, 0x020880, 0x400400, 0x400401,
0x005040, 0x200120, 0x400404, 0x0c0008,
0x000240, 0x000241, 0x000242, 0x021010,
0x000244, 0x046000, 0x010120, 0x400808,
0x000248, 0x088020, 0x304000, 0x400804,
0x020480, 0x400802, 0x400801, 0x400800,
0x000250, 0x021002, 0x021001, 0x021000,
0x580000, 0x018080, 0x202400, 0x021004,
0x012800, 0x140400, 0x080180, 0x021008,
0x005020, 0x200140, 0x048200, 0x400810,
0x000260, 0x088008, 0x010104, 0x004480,
0x010102, 0x320000, 0x010100, 0x010101,
0x088001, 0x088000, 0x062000, 0x088002,
0x005010, 0x088004, 0x010108, 0x400820,
0x240080, 0x402100, 0x108800, 0x021020,
0x005008, 0x000e00, 0x010110, 0x0c0040,
0x005004, 0x088010, 0x400440, 0x210200,
0x005000, 0x005001, 0x005002, 0x102080,
0x000280, 0x000281, 0x000282, 0x050008,
0x000284, 0x401020, 0x004810, 0x022100,
0x000288, 0x050002, 0x050001, 0x050000,
0x020440, 0x184000, 0x208020, 0x050004,
0x000290, 0x082400, 0x004804, 0x700000,
0x004802, 0x018040, 0x004800, 0x004801,
0x109000, 0x020820, 0x080140, 0x050010,
0x442000, 0x200180, 0x004808, 0x001600,
0x0002a0, 0x401004, 0x1a0000, 0x004440,
0x401001, 0x401000, 0x208008, 0x401002,
0x006100, 0x020810, 0x208004, 0x050020,
0x208002, 0x401008, 0x208000, 0x208001,
0x240040, 0x020808, 0x013000, 0x008300,
0x100500, 0x401010, 0x004820, 0x0c0080,
0x020801, 0x020800, 0x400480, 0x020802,
0x090200, 0x020804, 0x208010, 0x102040,
0x0002c0, 0x100900, 0x40a000, 0x004420,
0x020408, 0x018010, 0x141000, 0x280200,
0x020404, 0x203000, 0x080110, 0x050040,
0x020400, 0x020401, 0x020402, 0x400880,
0x240020, 0x018004, 0x080108, 0x021080,
0x018001, 0x018000, 0x004840, 0x018002,
0x080102, 0x404200, 0x080100, 0x080101,
0x020410, 0x018008, 0x080104, 0x102020,
0x240010, 0x004402, 0x004401, 0x004400,
0x082800, 0x401040, 0x010180, 0x004404,
0x510000, 0x088080, 0x001a00, 0x004408,
0x020420, 0x040300, 0x208040, 0x102010,
0x240000, 0x240001, 0x240002, 0x004410,
0x240004, 0x018020, 0x420200, 0x102008,
0x240008, 0x020840, 0x080120, 0x102004,
0x005080, 0x102002, 0x102001, 0x102000,
0x000300, 0x000301, 0x000302, 0x484000,
0x000304, 0x200018, 0x010060, 0x022080,
0x000308, 0x200014, 0x028800, 0x101020,
0x200011, 0x200010, 0x044400, 0x200012,
0x000310, 0x20000c, 0x142000, 0x010c00,
0x200009, 0x200008, 0x409000, 0x20000a,
0x200005, 0x200004, 0x0800c0, 0x200006,
0x200001, 0x200000, 0x200003, 0x200002,
0x000320, 0x060400, 0x010044, 0x101008,
0x010042, 0x00c800, 0x010040, 0x010041,
0x006080, 0x101002, 0x101001, 0x101000,
0x4a0000, 0x200030, 0x010048, 0x101004,
0x081800, 0x402040, 0x224000, 0x008280,
0x100480, 0x200028, 0x010050, 0x0c0100,
0x058000, 0x200024, 0x400500, 0x101010,
0x200021, 0x200020, 0x002a00, 0x200022,
0x000340, 0x100880, 0x010024, 0x248000,
0x010022, 0x081400, 0x010020, 0x010021,
0x441000, 0x034000, 0x080090, 0x002600,
0x10a000, 0x200050, 0x010028, 0x400900,
0x00c400, 0x402020, 0x080088, 0x021100,
0x060800, 0x200048, 0x010030, 0x104200,
0x080082, 0x200044, 0x080080, 0x080081,
0x200041, 0x200040, 0x080084, 0x200042,
0x010006, 0x402010, 0x010004, 0x010005,
0x010002, 0x010003, 0x010000, 0x010001,
0x200c00, 0x088100, 0x01000c, 0x101040,
0x01000a, 0x040280, 0x010008, 0x010009,
0x402001, 0x402000, 0x010014, 0x402002,
0x010012, 0x402004, 0x010010, 0x010011,
0x120200, 0x402008, 0x0800a0, 0x044800,
0x005100, 0x200060, 0x010018, 0x028400,
0x000380, 0x100840, 0x201400, 0x022004,
0x0c8000, 0x022002, 0x022001, 0x022000,
0x006020, 0x408400, 0x080050, 0x050100,
0x011800, 0x200090, 0x500200, 0x022008,
0x430000, 0x045000, 0x080048, 0x008220,
0x100420, 0x200088, 0x004900, 0x022010,
0x080042, 0x200084, 0x080040, 0x080041,
0x200081, 0x200080, 0x080044, 0x200082,
0x006008, 0x290000, 0x440800, 0x008210,
0x100410, 0x401100, 0x0100c0, 0x022020,
0x006000, 0x006001, 0x006002, 0x101080,
0x006004, 0x040240, 0x208100, 0x080c00,
0x100404, 0x008202, 0x008201, 0x008200,
0x100400, 0x100401, 0x100402, 0x008204,
0x006010, 0x020900, 0x080060, 0x008208,
0x100408, 0x2000a0, 0x061000, 0x414000,
0x100801, 0x100800, 0x080018, 0x100802,
0x604000, 0x100804, 0x0100a0, 0x022040,
0x080012, 0x100808, 0x080010, 0x080011,
0x020500, 0x040220, 0x080014, 0x00d000,
0x08000a, 0x100810, 0x080008, 0x080009,
0x003200, 0x018100, 0x08000c, 0x440400,
0x080002, 0x080003, 0x080000, 0x080001,
0x080006, 0x2000c0, 0x080004, 0x080005,
0x029000, 0x100820, 0x010084, 0x004500,
0x010082, 0x040208, 0x010080, 0x010081,
0x006040, 0x040204, 0x080030, 0x620000,
0x040201, 0x040200, 0x010088, 0x040202,
0x240100, 0x402080, 0x080028, 0x008240,
0x100440, 0x0a4000, 0x010090, 0x201800,
0x080022, 0x011400, 0x080020, 0x080021,
0x408800, 0x040210, 0x080024, 0x102100,
0x000400, 0x000401, 0x000402, 0x000403,
0x000404, 0x000405, 0x000406, 0x108200,
0x000408, 0x000409, 0x00040a, 0x002140,
0x00040c, 0x4c0000, 0x210800, 0x001090,
0x000410, 0x000411, 0x000412, 0x244000,
0x000414, 0x000860, 0x0a0100, 0x001088,
0x000418, 0x038000, 0x400220, 0x001084,
0x106000, 0x001082, 0x001081, 0x001080,
0x000420, 0x000421, 0x000422, 0x091000,
0x000424, 0x000850, 0x042080, 0x600100,
0x000428, 0x300080, 0x400210, 0x048800,
0x009100, 0x012200, 0x180040, 0x024400,
0x000430, 0x000844, 0x400208, 0x122000,
0x000841, 0x000840, 0x01c000, 0x000842,
0x400202, 0x084100, 0x400200, 0x400201,
0x260000, 0x000848, 0x400204, 0x0010a0,
0x000440, 0x000441, 0x000442, 0x002108,
0x000444, 0x000830, 0x405000, 0x070000,
0x000448, 0x002102, 0x002101, 0x002100,
0x020280, 0x20c000, 0x180020, 0x002104,
0x000450, 0x000824, 0x110080, 0x488000,
0x000821, 0x000820, 0x202200, 0x000822,
0x281000, 0x140200, 0x024800, 0x002110,
0x410100, 0x000828, 0x048400, 0x0010c0,
0x000460, 0x000814, 0x228000, 0x004280,
0x000811, 0x000810, 0x180008, 0x000812,
0x054000, 0x421000, 0x180004, 0x002120,
0x180002, 0x000818, 0x180000, 0x180001,
0x000805, 0x000804, 0x041100, 0x000806,
0x000801, 0x000800, 0x000803, 0x000802,
0x00a080, 0x00080c, 0x400240, 0x210400,
0x000809, 0x000808, 0x180010, 0x00080a,
0x000480, 0x000481, 0x000482, 0x420800,
0x000484, 0x014100, 0x042020, 0x001018,
0x000488, 0x300020, 0x08c000, 0x001014,
0x020240, 0x001012, 0x001011, 0x001010,
0x000490, 0x082200, 0x110040, 0x00100c,
0x608000, 0x00100a, 0x001009, 0x001008,
0x040900, 0x001006, 0x001005, 0x001004,
0x001003, 0x001002, 0x001001, 0x001000,
0x0004a0, 0x300008, 0x042004, 0x004240,
0x042002, 0x0a8000, 0x042000, 0x042001,
0x300001, 0x300000, 0x030100, 0x300002,
0x404800, 0x300004, 0x042008, 0x001030,
0x025000, 0x450000, 0x280800, 0x008500,
0x100300, 0x0008c0, 0x042010, 0x001028,
0x00a040, 0x300010, 0x400280, 0x001024,
0x090400, 0x001022, 0x001021, 0x001020,
0x0004c0, 0x049000, 0x110010, 0x004220,
0x020208, 0x502000, 0x008900, 0x280400,
0x020204, 0x090800, 0x640000, 0x002180,
0x020200, 0x020201, 0x020202, 0x001050,
0x110002, 0x220100, 0x110000, 0x110001,
0x0c4000, 0x0008a0, 0x110004, 0x001048,
0x00a020, 0x404400, 0x110008, 0x001044,
0x020210, 0x001042, 0x001041, 0x001040,
0x480100, 0x004202, 0x004201, 0x004200,
0x211000, 0x000890, 0x042040, 0x004204,
0x00a010, 0x300040, 0x001c00, 0x004208,
0x020220, 0x040500, 0x180080, 0x418000,
0x00a008, 0x000884, 0x110020, 0x004210,
0x000881, 0x000880, 0x420400, 0x000882,
0x00a000, 0x00a001, 0x00a002, 0x0e0000,
0x00a004, 0x000888, 0x204100, 0x001060,
0x000500, 0x000501, 0x000502, 0x002048,
0x000504, 0x014080, 0x0a0010, 0x600020,
0x000508, 0x002042, 0x002041, 0x002040,
0x009020, 0x120800, 0x044200, 0x002044,
0x000510, 0x501000, 0x0a0004, 0x010a00,
0x0a0002, 0x04a000, 0x0a0000, 0x0a0001,
0x040880, 0x084020, 0x308000, 0x002050,
0x410040, 0x200600, 0x0a0008, 0x001180,
0x000520, 0x060200, 0x104800, 0x600004,
0x009008, 0x600002, 0x600001, 0x600000,
0x009004, 0x084010, 0x030080, 0x002060,
0x009000, 0x009001, 0x009002, 0x600008,
0x212000, 0x084008, 0x041040, 0x008480,
0x100280, 0x000940, 0x0a0020, 0x600010,
0x084001, 0x084000, 0x400300, 0x084002,
0x009010, 0x084004, 0x002c00, 0x150000,
0x000540, 0x00200a, 0x002009, 0x002008,
0x340000, 0x081200, 0x008880, 0x00200c,
0x002003, 0x002002, 0x002001, 0x002000,
0x410010, 0x002006, 0x002005, 0x002004,
0x00c200, 0x220080, 0x041020, 0x002018,
0x410008, 0x000920, 0x0a0040, 0x104400,
0x410004, 0x002012, 0x002011, 0x002010,
0x410000, 0x410001, 0x410002, 0x002014,
0x480080, 0x118000, 0x041010, 0x002028,
0x026000, 0x000910, 0x010600, 0x600040,
0x200a00, 0x002022, 0x002021, 0x002020,
0x009040, 0x040480, 0x180100, 0x002024,
0x041002, 0x000904, 0x041000, 0x041001,
0x000901, 0x000900, 0x041004, 0x000902,
0x120400, 0x084040, 0x041008, 0x002030,
0x410020, 0x000908, 0x204080, 0x028200,
0x000580, 0x014004, 0x201200, 0x1c0000,
0x014001, 0x014000, 0x008840, 0x014002,
0x040810, 0x408200, 0x030020, 0x0020c0,
0x282000, 0x014008, 0x500400, 0x001110,
0x040808, 0x220040, 0x406000, 0x008420,
0x100220, 0x014010, 0x0a0080, 0x001108,
0x040800, 0x040801, 0x040802, 0x001104,
0x040804, 0x001102, 0x001101, 0x001100,
0x480040, 0x003800, 0x030008, 0x008410,
0x100210, 0x014020, 0x042100, 0x600080,
0x030002, 0x300100, 0x030000, 0x030001,
0x009080, 0x040440, 0x030004, 0x080a00,
0x100204, 0x008402, 0x008401, 0x008400,
0x100200, 0x100201, 0x100202, 0x008404,
0x040820, 0x084080, 0x030010, 0x008408,
0x100208, 0x422000, 0x204040, 0x001120,
0x480020, 0x220010, 0x008804, 0x002088,
0x008802, 0x014040, 0x008800, 0x008801,
0x105000, 0x002082, 0x002081, 0x002080,
0x020300, 0x040420, 0x008808, 0x002084,
0x220001, 0x220000, 0x110100, 0x220002,
0x003400, 0x220004, 0x008810, 0x440200,
0x040840, 0x220008, 0x080600, 0x002090,
0x410080, 0x188000, 0x204020, 0x001140,
0x480000, 0x480001, 0x480002, 0x004300,
0x480004, 0x040408, 0x008820, 0x121000,
0x480008, 0x040404, 0x030040, 0x0020a0,
0x040401, 0x040400, 0x204010, 0x040402,
0x480010, 0x220020, 0x041080, 0x008440,
0x100240, 0x000980, 0x204008, 0x092000,
0x00a100, 0x011200, 0x204004, 0x500800,
0x204002, 0x040410, 0x204000, 0x204001,
0x000600, 0x000601, 0x000602, 0x108004,
0x000604, 0x108002, 0x108001, 0x108000,
0x000608, 0x005800, 0x400030, 0x2a0000,
0x0200c0, 0x012020, 0x044100, 0x108008,
0x000610, 0x082080, 0x400028, 0x010900,
0x051000, 0x424000, 0x202040, 0x108010,
0x400022, 0x140040, 0x400020, 0x400021,
0x088800, 0x200500, 0x400024, 0x001280,
0x000620, 0x060100, 0x400018, 0x0040c0,
0x284000, 0x012008, 0x021800, 0x108020,
0x400012, 0x012004, 0x400010, 0x400011,
0x012001, 0x012000, 0x400014, 0x012002,
0x40000a, 0x209000, 0x400008, 0x400009,
0x100180, 0x000a40, 0x40000c, 0x0c0400,
0x400002, 0x400003, 0x400000, 0x400001,
0x400006, 0x012010, 0x400004, 0x400005,
0x000640, 0x610000, 0x0c0800, 0x0040a0,
0x020088, 0x081100, 0x202010, 0x108040,
0x020084, 0x140010, 0x019000, 0x002300,
0x020080, 0x020081, 0x020082, 0x400c00,
0x00c100, 0x140008, 0x202004, 0x021400,
0x202002, 0x000a20, 0x202000, 0x202001,
0x140001, 0x140000, 0x400060, 0x140002,
0x020090, 0x140004, 0x202008, 0x094000,
0x103000, 0x004082, 0x004081, 0x004080,
0x448000, 0x000a10, 0x010500, 0x004084,
0x200900, 0x088400, 0x400050, 0x004088,
0x0200a0, 0x012040, 0x180200, 0x241000,
0x0b0000, 0x000a04, 0x400048, 0x004090,
0x000a01, 0x000a00, 0x202020, 0x000a02,
0x400042, 0x140020, 0x400040, 0x400041,
0x005400, 0x000a08, 0x400044, 0x028100,
0x000680, 0x082010, 0x201100, 0x004060,
0x020048, 0x240800, 0x490000, 0x108080,
0x020044, 0x408100, 0x102800, 0x050400,
0x020040, 0x020041, 0x020042, 0x001210,
0x082001, 0x082000, 0x068000, 0x082002,
0x100120, 0x082004, 0x004c00, 0x001208,
0x214000, 0x082008, 0x4000a0, 0x001204,
0x020050, 0x001202, 0x001201, 0x001200,
0x018800, 0x004042, 0x004041, 0x004040,
0x100110, 0x401400, 0x042200, 0x004044,
0x0c1000, 0x300200, 0x400090, 0x004048,
0x020060, 0x012080, 0x208400, 0x080900,
0x100104, 0x082020, 0x400088, 0x004050,
0x100100, 0x100101, 0x100102, 0x230000,
0x400082, 0x020c00, 0x400080, 0x400081,
0x100108, 0x04c000, 0x400084, 0x001220,
0x02000c, 0x004022, 0x004021, 0x004020,
0x020008, 0x020009, 0x02000a, 0x004024,
0x020004, 0x020005, 0x020006, 0x004028,
0x020000, 0x020001, 0x020002, 0x020003,
0x401800, 0x082040, 0x110200, 0x004030,
0x020018, 0x018400, 0x202080, 0x440100,
0x020014, 0x140080, 0x080500, 0x208800,
0x020010, 0x020011, 0x020012, 0x001240,
0x004003, 0x004002, 0x004001, 0x004000,
0x020028, 0x004006, 0x004005, 0x004004,
0x020024, 0x00400a, 0x004009, 0x004008,
0x020020, 0x020021, 0x020022, 0x00400c,
0x240400, 0x004012, 0x004011, 0x004010,
0x100140, 0x000a80, 0x089000, 0x004014,
0x00a200, 0x011100, 0x4000c0, 0x004018,
0x020030, 0x680000, 0x050800, 0x102400,
0x000700, 0x060020, 0x201080, 0x010810,
0x402800, 0x081040, 0x044008, 0x108100,
0x190000, 0x408080, 0x044004, 0x002240,
0x044002, 0x200410, 0x044000, 0x044001,
0x00c040, 0x010802, 0x010801, 0x010800,
0x1000a0, 0x200408, 0x0a0200, 0x010804,
0x023000, 0x200404, 0x400120, 0x010808,
0x200401, 0x200400, 0x044010, 0x200402,
0x060001, 0x060000, 0x08a000, 0x060002,
0x100090, 0x060004, 0x010440, 0x600200,
0x200840, 0x060008, 0x400110, 0x101400,
0x009200, 0x012100, 0x044020, 0x080880,
0x100084, 0x060010, 0x400108, 0x010820,
0x100080, 0x100081, 0x100082, 0x007000,
0x400102, 0x084200, 0x400100, 0x400101,
0x100088, 0x200420, 0x400104, 0x028040,
0x00c010, 0x081004, 0x520000, 0x002208,
0x081001, 0x081000, 0x010420, 0x081002,
0x200820, 0x002202, 0x002201, 0x002200,
0x020180, 0x081008, 0x044040, 0x002204,
0x00c000, 0x00c001, 0x00c002, 0x010840,
0x00c004, 0x081010, 0x202100, 0x440080,
0x00c008, 0x140100, 0x080480, 0x002210,
0x410200, 0x200440, 0x101800, 0x028020,
0x200808, 0x060040, 0x010404, 0x004180,
0x010402, 0x081020, 0x010400, 0x010401,
0x200800, 0x200801, 0x200802, 0x002220,
0x200804, 0x504000, 0x010408, 0x028010,
0x00c020, 0x402400, 0x041200, 0x380000,
0x1000c0, 0x000b00, 0x010410, 0x028008,
0x200810, 0x011080, 0x400140, 0x028004,
0x0c2000, 0x028002, 0x028001, 0x028000,
0x201002, 0x408008, 0x201000, 0x201001,
0x100030, 0x014200, 0x201004, 0x022400,
0x408001, 0x408000, 0x201008, 0x408002,
0x020140, 0x408004, 0x044080, 0x080820,
0x100024, 0x082100, 0x201010, 0x010880,
0x100020, 0x100021, 0x100022, 0x440040,
0x040a00, 0x408010, 0x080440, 0x124000,
0x100028, 0x200480, 0x01a000, 0x001300,
0x100014, 0x060080, 0x201020, 0x004140,
0x100010, 0x100011, 0x100012, 0x080808,
0x006400, 0x408020, 0x030200, 0x080804,
0x100018, 0x080802, 0x080801, 0x080800,
0x100004, 0x100005, 0x100006, 0x008600,
0x100000, 0x100001, 0x100002, 0x100003,
0x10000c, 0x011040, 0x400180, 0x242000,
0x100008, 0x100009, 0x10000a, 0x080810,
0x052000, 0x100c00, 0x201040, 0x004120,
0x020108, 0x081080, 0x008a00, 0x440010,
0x020104, 0x408040, 0x080410, 0x002280,
0x020100, 0x020101, 0x020102, 0x310000,
0x00c080, 0x220200, 0x080408, 0x440004,
0x100060, 0x440002, 0x440001, 0x440000,
0x080402, 0x011020, 0x080400, 0x080401,
0x020110, 0x006800, 0x080404, 0x440008,
0x480200, 0x004102, 0x004101, 0x004100,
0x100050, 0x20a000, 0x010480, 0x004104,
0x200880, 0x011010, 0x148000, 0x004108,
0x020120, 0x040600, 0x403000, 0x080840,
0x100044, 0x011008, 0x022800, 0x004110,
0x100040, 0x100041, 0x100042, 0x440020,
0x011001, 0x011000, 0x080420, 0x011002,
0x100048, 0x011004, 0x204200, 0x028080,
};
/*! \brief Hamming 15,11 - Mask to select which bits to use for each ECC bit */
static const uint32_t _ham1511_mask_tbl[] = {
0x7f08, 0x78e4, 0x66d2, 0x55b1
};
/*! \brief Hamming 15,11 - Correction table (bit index to flip for each syndrome) */
static const int _ham1511_fix_tbl[] = {
-1, 0, 1, 4, 2, 5, 6, 7, 3, 8, 9, 10, 11, 12, 13, 14
};
/*! @} */
#endif /* __OSMO_IR77_AMBE_ECC_TABLES_H__ */

483
codec/frame.c Normal file
View File

@ -0,0 +1,483 @@
/* Iridium AMBE vocoder - Speech parameters to/from frame */
/* (C) 2015 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 Iridium AMBE speech parameters to/from frame
*/
#include <stdint.h>
#include <stdio.h> /* DEBUG */
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <osmocom/core/bits.h>
#include "private.h"
/*! \brief Apply/Remove interleaving
* Can be used to do both intra & inter using il_step
* \param[inout] lin_buf Linear bit buffer
* \param[inout] il_buf Interleaved bit buffer
* \param[in] il_step step to use when accesing il_buf
* \param[in] N Number of bits
* \param[in] dir Directon (0=interleave 1=de-interleave)
*/
void
ir77_ambe_interleave(ubit_t *lin_buf, ubit_t *il_buf,
int il_step, int N, int dir)
{
int div, mod;
int lin_idx, il_idx;
int i, j;
div = N / 24;
mod = N % 24;
il_idx = 0;
i = j = 0;
for (lin_idx=0; lin_idx<N; lin_idx++)
{
/* Data move */
if (dir)
lin_buf[lin_idx] = il_buf[il_idx];
else
il_buf[il_idx] = lin_buf[lin_idx];
/* Next index */
i++;
if (i == 24) {
i = 0;
il_idx = il_step * ++j;
} else
il_idx += il_step * (div + ((i > mod) ? 0 : 1));
}
}
/*! \brief Apply/Remove the scramnling
* \param[out] out Output unpacked bit buffer (can be == in)
* \param[in] in Input unpacked bit buffer
* \param[in] N Number of bits
* \param[in] seed Seed value of the PRNG
*/
void
ir77_ambe_scramble(ubit_t *out, ubit_t *in, int N, uint32_t seed)
{
uint32_t v;
int i;
v = seed << 3;
for (i=0; i<N; i++)
{
v = ((v * 173) + 13849) & 0xffff;
out[i] = in[i] ^ (v >> 15);
}
}
/*! \brief Apply or remove prioritization of bits
* \param[inout] lin_buf Buffer containing linearized bits
* \param[inout] prio_buf Buffer containing prioritized bits
* \param[in] dir Directon (0=prioritize 1=de-prioritize)
*/
void
ir77_ambe_prioritize(ubit_t *lin_buf, ubit_t *prio_buf, int dir)
{
int lin_idx, prio_idx, i, j;
prio_idx = 0;
for (i=0; ir77_ambe_prio_tbl[i].len; i++)
{
lin_idx = ir77_ambe_prio_tbl[i].pos;
for (j=0; j<ir77_ambe_prio_tbl[i].len; j++)
{
if (dir)
lin_buf[lin_idx] = prio_buf[prio_idx];
else
prio_buf[lin_idx] = lin_buf[prio_idx];
prio_idx++;
lin_idx++;
}
}
}
/*! \brief Grabs the requests bits from a frame (MSB first)
* \param[in] p Pointer to the first bit to read (MSB)
* \param[in] len Number of bits to grab (max 8)
* \returns The selected bits as a uint8_t
*/
static inline uint8_t
_get_bits(const ubit_t **p, int len)
{
uint8_t v = 0;
while (len--)
v = (v << 1) | *(*p)++;
return v;
}
/*! \brief Classify a frame into the different frame types
* \param[in] frame Frame data (as de-prioritized 103 ubits)
* \returns The frame type
*/
enum ir77_ambe_frame_type
ir77_ambe_frame_classify(const ubit_t *frame)
{
const ubit_t *p = frame;
uint8_t t;
t = _get_bits(&p, 4);
if (t == 0xf) {
/* Special */
t = _get_bits(&p, 2);
switch (t) {
case 0:
return AMBE_SILENCE;
case 1:
return AMBE_TONE;
default:
return AMBE_INVALID;
}
} else {
return AMBE_SPEECH;
}
}
/*! \brief Unpacks a frame into its raw encoded parameters
* \param[out] rp Encoded frame raw parameters to unpack into
* \param[in] frame Frame data (as de-prioritized 103 ubits)
*/
void
ir77_ambe_frame_unpack_raw(struct ir77_ambe_raw_params *rp, const ubit_t *frame)
{
const ubit_t *p = frame;
int i;
rp->pitch_mean = _get_bits(&p, 4);
rp->pitch_diff = _get_bits(&p, 6);
rp->gain_mean = _get_bits(&p, 5);
rp->gain_diff = _get_bits(&p, 5);
rp->v_uv[0] = _get_bits(&p, 4);
rp->v_uv[1] = _get_bits(&p, 4);
rp->prba_sum12 = _get_bits(&p, 8);
rp->prba_sum34 = _get_bits(&p, 6);
rp->prba_sum57 = _get_bits(&p, 7);
rp->prba_dif13 = _get_bits(&p, 8);
rp->prba_dif47 = _get_bits(&p, 6);
for (i=0; i<4; i++)
{
rp->hoc_sum[i] = _get_bits(&p, 7);
rp->hoc_dif[i] = _get_bits(&p, 3);
}
#ifdef DEBUG
printf("--- RAW frame:\n");
for (i=0; i<103; i++)
printf("%d", frame[i]);
printf("\n");
printf("--- RAW params:\n");
printf(" .pitch_mean : %3d\n", rp->pitch_mean);
printf(" .pitch_diff : %3d\n", rp->pitch_diff);
printf(" .gain_mean : %3d\n", rp->gain_mean);
printf(" .gain_diff : %3d\n", rp->gain_diff);
printf(" .v_uv[0] : %3d\n", rp->v_uv[0]);
printf(" .v_uv[1] : %3d\n", rp->v_uv[1]);
printf(" .prba_sum12 : %3d\n", rp->prba_sum12);
printf(" .prba_sum34 : %3d\n", rp->prba_sum34);
printf(" .prba_sum57 : %3d\n", rp->prba_sum57);
printf(" .prba_dif13 : %3d\n", rp->prba_dif13);
printf(" .prba_dif47 : %3d\n", rp->prba_dif47);
for (i=0; i<4; i++)
{
printf(" .hoc_sum[%d] : %3d\n", i, rp->hoc_sum[i]);
printf(" .hoc_dif[%d] : %3d\n", i, rp->hoc_dif[i]);
}
#endif
}
/*! \brief Computes and fill-in f0, L and Lb vaues for a given subframe
* (from f0log_mean and f0log_diff)
* \param[out] sf Subframe
* \param[in] f0log_mean f0 mean value for this subframe pair
* \param[in] f0log_diff f0 diff value for this subframe
*/
static void
ir77_ambe_subframe_compute_f0_L_Lb(struct ir77_ambe_subframe *sf,
float f0log_mean, float f0log_diff)
{
float f0;
sf->f0log = f0log_mean + f0log_diff;
f0 = powf(2.0f, sf->f0log);
f0 = fmaxf(fminf(f0, 0.05222f), 0.00810f);
sf->f0 = f0;
sf->L = (int)floorf(0.4627f / sf->f0);
sf->L = (sf->L < 9) ? 9 : ((sf->L > 56) ? 56 : sf->L);
sf->Lb[0] = ir77_ambe_hpg_tbl[sf->L - 9][0];
sf->Lb[1] = ir77_ambe_hpg_tbl[sf->L - 9][1];
sf->Lb[2] = ir77_ambe_hpg_tbl[sf->L - 9][2];
sf->Lb[3] = ir77_ambe_hpg_tbl[sf->L - 9][3];
#ifdef DEBUG
printf("---- Decoded f0/L/Lb\n");
printf(" .f0log_mean : %f\n", f0log_mean);
printf(" .f0log_diff : %f\n", f0log_diff);
printf(" .f0 : %f [%04x]\n", f0, (int)(roundf(f0 * (1<<19))));
printf(" .L : %d\n", sf->L);
printf(" .Lb0 : %d\n", sf->Lb[0]);
printf(" .Lb1 : %d\n", sf->Lb[1]);
printf(" .Lb2 : %d\n", sf->Lb[2]);
printf(" .Lb3 : %d\n", sf->Lb[3]);
#endif
}
/*! \brief Resample and "ac-couple" (remove mean) a magnitude array to a new L
* \param[in] mag_dst Destination magnitude array (L_dst elements)
* \param[in] L_dst Target number of magnitudes
* \param[in] mag_src Source magnitude array (L_src elements)
* \param[in] L_src Source number of magnitudes
*/
static void
ir77_ambe_resample_mag(float *mag_dst, int L_dst, float *mag_src, int L_src)
{
float avg, step, pos;
int i;
avg = 0.0f;
step = (float)L_src / (float)L_dst;
pos = step;
for (i=0; i<L_dst; i++)
{
int posi = (int)floorf(pos);
if (posi == 0) {
mag_dst[i] = mag_src[0];
} else if (posi >= L_src) {
mag_dst[i] = mag_src[L_src-1];
} else {
float alpha = pos - posi;
mag_dst[i] = mag_src[posi-1] * (1.0f - alpha)
+ mag_src[posi] * alpha;
}
avg += mag_dst[i];
pos += step;
}
avg /= L_dst;
for (i=0; i<L_dst; i++)
mag_dst[i] -= avg;
}
/*! \brief Decodes the speech parameters for both subframes from raw params
* \param[out] sf Array of 2 subframes data to fill-in
* \param[in] sf_prev Previous subframe 1 data
* \param[in] rp Encoded frame raw parameters
*/
void
ir77_ambe_frame_decode_params(struct ir77_ambe_subframe *sf,
struct ir77_ambe_subframe *sf_prev,
struct ir77_ambe_raw_params *rp)
{
float f0log, gain;
int i, j;
/* f0 / L / Lb for each subframe */
f0log = -4.4f - 1.777e-1f * rp->pitch_mean;
for (i=0; i<2; i++)
ir77_ambe_subframe_compute_f0_L_Lb(&sf[i],
f0log, ir77_ambe_pitch_diff_vq[rp->pitch_diff][i]);
/* Gain */
gain = 0.34375f * (rp->gain_mean + 0.5f);
for (i=0; i<2; i++)
sf[i].gain = gain + ir77_ambe_gain_diff_vq[rp->gain_diff][i] - (0.5f * log2f(sf[i].L));
#ifdef DEBUG
printf("---- Decoded Gain\n");
printf(" .mean : %f\n", gain);
printf(" .diff0 : %f\n", ir77_ambe_gain_diff_vq[rp->gain_diff][0]);
printf(" .diff1 : %f\n", ir77_ambe_gain_diff_vq[rp->gain_diff][1]);
printf(" .final0 : %f [%04x]\n", sf[0].gain, (int)(roundf(2048.0f * sf[0].gain)));
printf(" .final1 : %f [%04x]\n", sf[1].gain, (int)(roundf(2048.0f * sf[1].gain)));
#endif
/* V/UV */
for (i=0; i<2; i++)
{
uint8_t v_uv = ir77_ambe_v_uv_tbl[rp->v_uv[i]];
for (j=0; j<8; j++)
sf[i].v_uv[j] = (v_uv >> (7-j)) & 1;
}
#ifdef DEBUG
printf("---- Decode V/UV\n");
printf(" .v_uv[0] : ");
for (i=0; i<8; i++)
printf("%d", sf[0].v_uv[i]);
printf("\n");
printf(" .v_uv[1] : ");
for (i=0; i<8; i++)
printf("%d", sf[1].v_uv[i]);
printf("\n");
#endif
/* Spectral magnitudes */
for (i=0; i<2; i++)
{
int j, k, l;
/* Prediction */
ir77_ambe_resample_mag(sf[i].Mlog, sf[i].L, sf_prev->Mlog, sf_prev->L);
for (j=0; j<sf[i].L; j++)
sf[i].Mlog[j] *= 0.8f;
/* PRBA */
float d = (i == 0) ? -1.0f : 1.0f;
float prba[8];
float Ri[8];
prba[0] = 0.0f;
prba[1] = ir77_ambe_prba_sum12_vq[rp->prba_sum12][0] +
d * ir77_ambe_prba_dif13_vq[rp->prba_dif13][0];
prba[2] = ir77_ambe_prba_sum12_vq[rp->prba_sum12][1] +
d * ir77_ambe_prba_dif13_vq[rp->prba_dif13][1];
prba[3] = ir77_ambe_prba_sum34_vq[rp->prba_sum34][0] +
d * ir77_ambe_prba_dif13_vq[rp->prba_dif13][2];
prba[4] = ir77_ambe_prba_sum34_vq[rp->prba_sum34][1] +
d * ir77_ambe_prba_dif47_vq[rp->prba_dif47][0];
prba[5] = ir77_ambe_prba_sum57_vq[rp->prba_sum57][0] +
d * ir77_ambe_prba_dif47_vq[rp->prba_dif47][1];
prba[6] = ir77_ambe_prba_sum57_vq[rp->prba_sum57][1] +
d * ir77_ambe_prba_dif47_vq[rp->prba_dif47][2];
prba[7] = ir77_ambe_prba_sum57_vq[rp->prba_sum57][2] +
d * ir77_ambe_prba_dif47_vq[rp->prba_dif47][3];
ir77_ambe_idct(Ri, prba, 8, 8);
/* Process each block */
float rconst = (1.0f / (2.0f * (float)M_SQRT2));
float sum = 0.0f;
k = 0;
for (j=0; j<4; j++) {
const float *hoc_sum_tbl[] = {
ir77_ambe_hoc0_sum_vq[rp->hoc_sum[0]],
ir77_ambe_hoc1_sum_vq[rp->hoc_sum[1]],
ir77_ambe_hoc2_sum_vq[rp->hoc_sum[2]],
ir77_ambe_hoc3_sum_vq[rp->hoc_sum[3]],
};
const float *hoc_dif_tbl[] = {
ir77_ambe_hoc0_dif_vq[rp->hoc_dif[0]],
ir77_ambe_hoc1_dif_vq[rp->hoc_dif[1]],
ir77_ambe_hoc2_dif_vq[rp->hoc_dif[2]],
ir77_ambe_hoc3_dif_vq[rp->hoc_dif[3]],
};
float C[6], c[17];
/* From PRBA through 2x2 xform */
C[0] = (Ri[j<<1] + Ri[(j<<1)+1]) * 0.5f;
C[1] = (Ri[j<<1] - Ri[(j<<1)+1]) * rconst;
/* HOC */
/* Default to use all available */
C[2] = hoc_sum_tbl[j][0] + d * hoc_dif_tbl[j][0];
C[3] = hoc_sum_tbl[j][1] + d * hoc_dif_tbl[j][1];
C[4] = hoc_sum_tbl[j][2] + d * hoc_dif_tbl[j][2];
C[5] = hoc_sum_tbl[j][3] + d * hoc_dif_tbl[j][3];
/* Zero unused value and if len differ for
* sf0/1, then diff vector is not used */
for (l=2; l<6; l++)
{
if (l >= sf[i].Lb[j])
C[l] = 0.0f;
else if (l >= sf[i^1].Lb[j])
C[l] = hoc_sum_tbl[j][l-2];
}
/* De-DCT */
ir77_ambe_idct(c, C, sf[i].Lb[j], (sf[i].Lb[j] < 6) ? sf[i].Lb[j] : 6);
/* Set magnitudes */
for (l=0; l<sf[i].Lb[j]; l++)
sf[i].Mlog[k++] += c[l];
sum += C[0] * sf[i].Lb[j];
}
/* Adjust to final gain value */
float ofs = sf[i].gain - (sum / sf[i].L);
for (j=0; j<sf[i].L; j++)
sf[i].Mlog[j] += ofs;
}
}
/*! \brief Expands the decoded subframe params to prepare for synthesis
* \param[in] sf The subframe to expand
*/
void
ir77_ambe_subframe_expand(struct ir77_ambe_subframe *sf)
{
float unvc;
int i;
sf->w0 = sf->f0 * (2.0f * M_PIf);
unvc = 0.2046f / sqrtf(sf->w0); /* ??? */
for (i=0; i<sf->L; i++) {
int j = (int)(i * 16.0f * sf->f0);
sf->Vl[i] = sf->v_uv[j];
sf->Ml[i] = powf(2.0, sf->Mlog[i]) / 8.0f;
if (!sf->Vl[i])
sf->Ml[i] *= unvc;
}
}
/*! @} */

199
codec/ir77_ambe_decode.c Normal file
View File

@ -0,0 +1,199 @@
/* Iridium AMBE vocoder - Decoder tool */
/* (C) 2015 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 "ambe.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 ir77_ambe_decoder *dec = 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 */
dec = ir77_ambe_decode_alloc();
if (!dec)
goto exit;
/* Process all frames */
l = 0;
while (!feof(fin))
{
uint8_t superframe[39];
int16_t audio[2*360];
int rv, i;
/* Read input frame */
rv = fread(superframe, 1, 39, fin);
if (rv != 39)
break;
/* Skip dummy frames */
if ((superframe[0] == 0xff) && (superframe[38] == 0xff))
continue;
/* Decompress */
rv = ir77_ambe_decode_superframe(dec, audio, 2*360, superframe);
if (rv) {
fprintf(stderr, "[!] codec error\n");
break;
}
/* Write audio output */
for (i=0; i<2*360; i++)
audio[i] = le16(audio[i]);
rv = fwrite(audio, 2, 2*360, fout);
if (rv != 2*360) {
fprintf(stderr, "[!] short write\n");
break;
}
/* Keep track of number of samples */
l += 2*360;
}
/* Release decoder */
ir77_ambe_decode_release(dec);
/* 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;
}

177
codec/math.c Normal file
View File

@ -0,0 +1,177 @@
/* Iridium AMBE vocoder - Math functions */
/* (C) 2015 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 Iridium AMBE vocoder math functions
*/
#include <math.h>
#include "private.h"
/*! \brief Table for \ref cosf_fast and \ref sinf_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 Fast Sinus approximation using a simple table
* \param[in] angle The angle value
* \returns The sinus of the angle
*/
float
sinf_fast(float angle)
{
const float f = 512.0f / M_PIf;
return cos_tbl[((int)(angle*f) + 768) & 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
ir77_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
ir77_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;
}
}
/*! \brief Forward Discrete Fourrier Transform (float->complex)
* \param[out] out_i Real component result buffer (freq domain, N/2+1 elements)
* \param[out] out_q Imag component result buffer (freq domain, N/2+1 elements)
* \param[in] in Input buffer (time domain, M elements)
* \param[in] N Number of points of the DFT
* \param[in] M Limit to to the number of available time domain elements
*
* Since the input is float, the result is symmetric and so only one side
* is computed. The output index 0 is DC.
*/
void
ir77_ambe_fdft_fc(float *out_i, float *out_q, float *in, int N, int M)
{
int fb, ts;
for (fb=0; fb<=(N/2); fb++)
{
float i=0.0f, q=0.0f;
for (ts=0; ts<M; ts++)
{
float angle = (- 2.0f * M_PIf / N) * fb * ts;
i += in[ts] * cosf_fast(angle);
q += in[ts] * sinf_fast(angle);
}
out_i[fb] = i;
out_q[fb] = q;
}
}
/*! \brief Inverse Discret Fourrier Transform (complex->float)
* \param[out] out Result buffer (time domain, M
* \param[in] in_i Real component input buffer (freq domain, N/2+1 elements)
* \param[in] in_q Imag component input buffer (freq domain, N/2+1 elements)
* \param[in] N Number of points of the DFT
* \param[in] M Limit to the number of time domain elements to generate
*
* The input is assumed to be symmetric and so only N/2+1 inputs are
* needed. DC component must be input index 0.
*/
void
ir77_ambe_idft_cf(float *out, float *in_i, float *in_q, int N, int M)
{
int fb, ts;
for (ts=0; ts<M; ts++)
{
float r=0.0f;
for (fb=0; fb<=(N/2); fb++)
{
float angle = (- 2.0f * M_PIf / N) * fb * ts;
float m = (fb == 0 || fb == (N/2)) ? 1.0f : 2.0f;
r += m * (in_i[fb] * cosf_fast(angle) + in_q[fb] * sinf_fast(angle));
}
out[ts] = r / N;
}
}
/*! @} */

178
codec/private.h Normal file
View File

@ -0,0 +1,178 @@
/* Iridium AMBE vocoder - private header */
/* (C) 2015 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_IR77_AMBE_PRIVATE_H__
#define __OSMO_IR77_AMBE_PRIVATE_H__
/*! \defgroup codec_private Iridium AMBE vocoder - internal API
* \ingroup codec
* @{
*/
/*! \file codec/private.h
* \brief Iridium AMBE vocoder private header
*/
#include <osmocom/core/bits.h>
#define AMBE_RATE 8000 /*!< \brief AMBE sample rate (Hz) */
/*! \brief AMBE possible frame types */
enum ir77_ambe_frame_type
{
AMBE_INVALID, /*!< \brief Invalid frame */
AMBE_SPEECH, /*!< \brief Speech frame */
AMBE_SILENCE, /*!< \brief Silence indication frame */
AMBE_TONE, /*!< \brief Tone frame */
};
/*! \brief AMBE encoded frame raw parameters */
struct ir77_ambe_raw_params
{
uint8_t pitch_mean; /*!< \brief Pitch mean value scalar quantized */
uint8_t pitch_diff; /*!< \brief Pitch diff VQ */
uint8_t gain_mean; /*!< \brief Gain mean value scalar quantized */
uint8_t gain_diff; /*!< \brief Gain diff VQ */
uint8_t v_uv[2]; /*!< \brief V/UV VQ for each subframe */
uint8_t prba_sum12; /*!< \brief PRBA Sum 1-2 VQ */
uint8_t prba_sum34; /*!< \brief PRBA Sum 3-4 VQ */
uint8_t prba_sum57; /*!< \brief PRBA Sum 5-7 VQ */
uint8_t prba_dif13; /*!< \brief PRBA Diff 1-3 VQ */
uint8_t prba_dif47; /*!< \brief PRBA Diff 4-7 VQ */
uint8_t hoc_sum[4]; /*!< \brief HOC Sum VQ for each block */
uint8_t hoc_dif[4]; /*!< \brief HOC Diff VQ for each block */
};
/*! \brief AMBE subframe parameters */
struct ir77_ambe_subframe
{
float f0; /*!< \brief fundamental normalized frequency */
float f0log; /*!< \brief log2(f0) */
float w0; /*!< \brief fundamental frequency (rad/samp) */
int L; /*!< \brief Number of harmonics */
int Lb[4]; /*!< \brief Harmonics per block */
int v_uv[8]; /*!< \brief Voicing state */
int Vl[56]; /*!< \brief Per-harmonic voicing state */
float gain; /*!< \brief Gain */
float Mlog[56]; /*!< \brief log spectral magnitudes */
float Ml[56]; /*!< \brief spectral magnitudes */
};
/*! \brief AMBE synthesizer state */
struct ir77_ambe_synth
{
int16_t u_prev; /*!< \brief Last 'u' of previous subframe */
float uw_prev[231]; /*!< \brief Unvoiced data from previous subframe */
float psi1; /*!< \brief Current PSI angle for fundamental */
float phi[56]; /*!< \brief Current phase for each harmonic */
float SE; /*!< \brief Current energy parameter */
};
/*! \brief AMBE decoder state */
struct ir77_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 ir77_ambe_subframe sf_prev; /*!< \brief Previous subframe */
struct ir77_ambe_synth synth; /*!< \brief Synthesizer state */
};
/* From ecc.c */
void ir77_ambe_golay23_encode(ubit_t *out, ubit_t *in);
int ir77_ambe_golay23_decode(ubit_t *out, ubit_t *in, uint32_t *data_p);
void ir77_ambe_golay24_encode(ubit_t *out, ubit_t *in);
int ir77_ambe_golay24_decode(ubit_t *out, ubit_t *in, uint32_t *data_p);
void ir77_ambe_hamming1511_encode(ubit_t *out, ubit_t *in);
int ir77_ambe_hamming1511_decode(ubit_t *out, ubit_t *in);
/* From frame.c */
void ir77_ambe_interleave(ubit_t *lin_buf, ubit_t *il_buf,
int il_step, int N, int dir);
void ir77_ambe_scramble(ubit_t *out, ubit_t *in, int N, uint32_t seed);
void ir77_ambe_prioritize(ubit_t *lin_buf, ubit_t *prio_buf, int dir);
enum ir77_ambe_frame_type ir77_ambe_frame_classify(const ubit_t *frame);
void ir77_ambe_frame_unpack_raw(struct ir77_ambe_raw_params *rp,
const ubit_t *frame);
void ir77_ambe_frame_decode_params(struct ir77_ambe_subframe *sf,
struct ir77_ambe_subframe *sf_prev,
struct ir77_ambe_raw_params *rp);
void ir77_ambe_subframe_expand(struct ir77_ambe_subframe *sf);
/* From synth.c */
void ir77_ambe_synth_init(struct ir77_ambe_synth *synth);
void ir77_ambe_synth_enhance(struct ir77_ambe_synth *synth, struct ir77_ambe_subframe *sf);
void ir77_ambe_synth_audio(struct ir77_ambe_synth *synth, int16_t *audio,
struct ir77_ambe_subframe *sf,
struct ir77_ambe_subframe *sf_prev);
/* From math.c */
#define M_PIf (3.141592653589793f) /*!< \brief Value of pi as a float */
float cosf_fast(float angle);
float sinf_fast(float angle);
void ir77_ambe_fdct(float *out, float *in, int N, int M);
void ir77_ambe_idct(float *out, float *in, int N, int M);
void ir77_ambe_fdft_fc(float *out_i, float *out_q, float *in, int N, int M);
void ir77_ambe_idft_cf(float *out, float *in_i, float *in_q, int N, int M);
/* From tables.c */
extern const struct { uint8_t pos; uint8_t len; } ir77_ambe_prio_tbl[];
extern const float ir77_ambe_pitch_diff_vq[64][2];
extern const uint8_t ir77_ambe_hpg_tbl[48][4];
extern const float ir77_ambe_gain_diff_vq[32][2];
extern const uint8_t ir77_ambe_v_uv_tbl[16];
extern const float ir77_ambe_prba_sum12_vq[256][2];
extern const float ir77_ambe_prba_sum34_vq[ 64][2];
extern const float ir77_ambe_prba_sum57_vq[128][3];
extern const float ir77_ambe_prba_dif13_vq[256][3];
extern const float ir77_ambe_prba_dif47_vq[ 64][4];
extern const float ir77_ambe_hoc0_sum_vq[128][4];
extern const float ir77_ambe_hoc0_dif_vq[128][4];
extern const float ir77_ambe_hoc1_sum_vq[128][4];
extern const float ir77_ambe_hoc1_dif_vq[128][4];
extern const float ir77_ambe_hoc2_sum_vq[128][4];
extern const float ir77_ambe_hoc2_dif_vq[128][4];
extern const float ir77_ambe_hoc3_sum_vq[128][4];
extern const float ir77_ambe_hoc3_dif_vq[128][4];
/* From tones.c */
int ir77_ambe_decode_tone(struct ir77_ambe_decoder *dec,
int16_t *audio, int N, const ubit_t *frame);
/*! @} */
#endif /* __OSMO_IR77_AMBE_PRIVATE_H__ */

381
codec/synth.c Normal file
View File

@ -0,0 +1,381 @@
/* Iridium AMBE vocoder - Speech synthesis */
/* (C) 2015 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/synth.c
* \brief Iridium AMBE vocoder speech synthesis
*/
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <string.h>
#include "private.h"
/*! \brief Synthesis window (49 samples overlap) */
static const float ws[] = {
0.00f, 0.02f,
0.04f, 0.06f, 0.08f, 0.10f, 0.12f, 0.14f, 0.16f, 0.18f,
0.20f, 0.22f, 0.24f, 0.26f, 0.28f, 0.30f, 0.32f, 0.34f,
0.36f, 0.38f, 0.40f, 0.42f, 0.44f, 0.46f, 0.48f, 0.50f,
0.52f, 0.54f, 0.56f, 0.58f, 0.60f, 0.62f, 0.64f, 0.66f,
0.68f, 0.70f, 0.72f, 0.74f, 0.76f, 0.78f, 0.80f, 0.82f,
0.84f, 0.86f, 0.88f, 0.90f, 0.92f, 0.94f, 0.96f, 0.98f,
1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f,
1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f,
1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f,
1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f,
1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f,
1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f,
1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f,
1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f,
1.00f, 1.00f, 1.00f,
1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f,
1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f,
1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f,
1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f,
1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f,
1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f,
1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f,
1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f,
0.98f, 0.96f, 0.94f, 0.92f, 0.90f, 0.88f, 0.86f, 0.84f,
0.82f, 0.80f, 0.78f, 0.76f, 0.74f, 0.72f, 0.70f, 0.68f,
0.66f, 0.64f, 0.62f, 0.60f, 0.58f, 0.56f, 0.54f, 0.52f,
0.50f, 0.48f, 0.46f, 0.44f, 0.42f, 0.40f, 0.38f, 0.36f,
0.34f, 0.32f, 0.30f, 0.28f, 0.26f, 0.24f, 0.22f, 0.20f,
0.18f, 0.16f, 0.14f, 0.12f, 0.10f, 0.08f, 0.06f, 0.04f,
0.02f, 0.00f,
};
/*! \brief Random phase increment (precomputed) */
static const float rho[] = {
3.002978f, -0.385743f, -1.804058f, 0.708389f, 3.080091f, 0.234237f,
-2.601564f, 2.564900f, 0.101063f, -0.241570f, -2.283176f, 0.460491f,
-1.611275f, 2.258339f, -2.055267f, 1.733923f, 2.517236f, -1.766211f,
0.897032f, -2.360999f, -0.280836f, -2.714514f, 2.100092f, 2.300326f,
-1.158767f, -2.044268f, -2.668387f, -2.578737f, 0.185036f, 1.551429f,
2.726814f, 2.655614f, 3.046857f, 0.834348f, -0.513595f, 1.466037f,
0.691121f, 0.127319f, -2.034924f, -1.070655f, 0.456588f, -2.278682f,
1.229021f, -2.139595f, -0.119750f, -0.301534f, 0.029391f, 0.068775f,
0.520336f, 2.339119f, -0.808328f, 1.332154f, 2.929768f, -0.338316f,
0.022767f, -1.063795f,
};
/*! \brief Generates random sequence of uint16_t according to spec
* \param[out] u_seq Result buffer
* \param[in] u_prev Last 'u' value of where to resume from
* \param[in] n Number of items to generate
*/
static void
ir77_ambe_gen_random(uint16_t *u_seq, uint16_t u_prev, int n)
{
uint32_t u = u_prev;
int i;
for (i=0; i<n; i++) {
u = (u * 171 + 11213) % 53125;
u_seq[i] = u;
}
}
/*! \brief Perform unvoiced synthesis
* \param[in] synth Synthesizer state structure
* \param[out] suv Result buffer (180 samples)
* \param[in] sf Expanded subframe data
*/
static void
ir77_ambe_synth_unvoiced(struct ir77_ambe_synth *synth, float *suv,
struct ir77_ambe_subframe *sf)
{
uint16_t u[231];
float uw[231];
float Uwi[129], Uwq[129];
int i, al, bl, l;
/* Generate the white noise sequence and window it with ws */
ir77_ambe_gen_random(u, synth->u_prev, 231);
synth->u_prev = u[179];
for (i=0; i<231; i++)
uw[i] = (float)u[i] * ws[i];
/* Compute the DFT */
ir77_ambe_fdft_fc(Uwi, Uwq, uw, 256, 231);
/* Apply the spectral magnitude */
bl = ceilf(256.0f / (2 * M_PIf) * (.5f) * sf->w0);
for (i=0; i<bl; i++) {
Uwi[i] = 0.0f;
Uwq[i] = 0.0f;
}
for (l=0; l<sf->L; l++)
{
float ampl;
/* Edges */
al = bl;
bl = ceilf(256.0f / (2 * M_PIf) * (l + 1.5f) * sf->w0);
/* Compute factor */
ampl = 0.0f;
for (i=al; i<bl; i++) {
ampl += Uwi[i] * Uwi[i] + Uwq[i] * Uwq[i];
}
ampl = 76.89f * sf->Ml[l] / sqrtf(ampl / (bl - al));
/* Set magnitude */
for (i=al; i<bl; i++) {
if (sf->Vl[l]) {
Uwi[i] = 0.0f;
Uwq[i] = 0.0f;
} else {
Uwi[i] *= ampl;
Uwq[i] *= ampl;
}
}
}
for (i=bl; i<=128; i++) {
Uwi[i] = 0.0f;
Uwq[i] = 0.0f;
}
/* Get time-domain samples via iDFT */
ir77_ambe_idft_cf(uw, Uwi, Uwq, 256, 231);
/* Weighted Overlap And Add */
for (i=0; i<66; i++) {
suv[i] = synth->uw_prev[i + 115];
}
for (i=66; i<115; i++) {
suv[i] = (ws[i + 115] * synth->uw_prev[i + 115] + ws[i - 65] * uw[i - 65])
/ (ws[i + 115] * ws[i + 115] + ws[i - 65] * ws[i - 65]);
}
for (i=115; i<180; i++) {
suv[i] = uw[i - 65];
}
memcpy(synth->uw_prev, uw, sizeof(float) * 231);
}
/*! \brief Perform voiced synthesis
* \param[in] synth Synthesizer state structure
* \param[out] sv Result buffer (180 samples)
* \param[in] sf Expanded subframe data for current subframe
* \param[in] sf_prev Expanded subframe data for prevous subframe
*/
static void
ir77_ambe_synth_voiced(struct ir77_ambe_synth *synth, float *sv,
struct ir77_ambe_subframe *sf,
struct ir77_ambe_subframe *sf_prev)
{
int i, l, L_max, L_uv;
/* Pre-clear */
memset(sv, 0x00, sizeof(float) * 180);
/* How many subband to process */
L_max = sf_prev->L > sf->L ? sf_prev->L : sf->L;
/* psi update */
L_uv = 0;
for (l=0; l<L_max; l++)
L_uv += sf->Vl[l] ? 0 : 1;
synth->psi1 = remainderf(synth->psi1 + (sf->w0 + sf_prev->w0) * 90.0f, 2 * M_PIf);
/* Scan each band */
for (l=0; l<L_max; l++)
{
int Vl_cur, Vl_prev;
float Ml_cur, Ml_prev;
float phi_cur, phi_prev;
float w_cur, w_prev;
int fine;
/* Handle out-of-bound for Vl and Ml */
Vl_cur = l >= sf->L ? 0 : sf->Vl[l];
Vl_prev = l >= sf_prev->L ? 0 : sf_prev->Vl[l];
Ml_cur = l >= sf->L ? 0.0f : sf->Ml[l];
Ml_prev = l >= sf_prev->L ? 0.0f : sf_prev->Ml[l];
/* Phase and Angular speed */
w_cur = (l+1) * sf->w0;
w_prev = (l+1) * sf_prev->w0;
phi_prev = synth->phi[l];
phi_cur = synth->psi1 * (l+1);
if (l >= (sf->L / 4))
phi_cur += ((float)L_uv / (float)sf->L) * rho[l];
synth->phi[l] = phi_cur;
/* Actual synthesis */
/* Can we do a fine transistion ? */
fine = Vl_cur && Vl_prev && (l < 7) && (fabsf(w_cur - w_prev) < (.1f * w_cur));
/* Fine transition */
if (fine)
{
float Ml_step = (Ml_cur - Ml_prev) / 180.0f;
float Dpl = phi_cur - phi_prev - (w_cur + w_prev) * 90.0f;
float Dwl = (Dpl - 2 * M_PIf * floorf((Dpl + M_PIf) / (2 * M_PIf))) / 180.0f;
float THa = w_prev + Dwl;
float THb = (w_cur - w_prev) / 360.0f;
for (i=0; i<180; i++)
sv[i] += (Ml_prev + i * Ml_step) * cosf_fast(
phi_prev + (THa + THb * i) * i
);
}
/* Coarse transition: Current frame (if voiced) */
if (!fine && Vl_cur)
{
for (i=66; i<180; i++)
sv[i] += ws[i-65] * Ml_cur * cosf_fast(phi_cur + w_cur * (i - 180));
}
/* Coarse transition: Previous frame (if voiced) */
if (!fine && Vl_prev)
{
for (i=0; i<115; i++)
sv[i] += ws[i+115] * Ml_prev * cosf_fast(phi_prev + w_prev * i);
}
}
/* Still need to update phi for the rest of the bands */
for (l=L_max; l<56; l++)
synth->phi[l] = (synth->psi1 * (l+1)) + (((float)L_uv / (float)sf->L) * rho[l]);
}
/*! \brief Initialized Synthesizer state
* \param[out] synth The structure to reset
*/
void
ir77_ambe_synth_init(struct ir77_ambe_synth *synth)
{
memset(synth, 0x00, sizeof(struct ir77_ambe_synth));
synth->u_prev = 3147;
}
/*! \brief Apply the spectral magnitude enhancement on the subframe
* \param[in] synth Synthesizer state structure
* \param[in] sf Expanded subframe data for subframe to enhance
*/
void
ir77_ambe_synth_enhance(struct ir77_ambe_synth *synth,
struct ir77_ambe_subframe *sf)
{
float rm0, rm1;
float k1, k2, k3;
float gamma;
int l;
/* Compute RM0 and RM1 */
rm0 = 0.0f;
rm1 = 0.0f;
for (l=0; l<sf->L; l++)
{
float sq = sf->Ml[l] * sf->Ml[l];
rm0 += sq;
rm1 += sq * cosf_fast(sf->w0 * (l+1));
}
/* Pre compute some constants */
k1 = 0.96f * M_PIf / (sf->w0 * rm0 * (rm0 * rm0 - rm1 * rm1));
k2 = rm0 * rm0 + rm1 * rm1;
k3 = 2.0f * rm0 * rm1;
/* Apply to the amplitudes */
gamma = 0.0f;
for (l=0; l<sf->L; l++)
{
float w;
if ( (l+1)*8 <= sf->L ) {
w = 1.0f;
} else {
w = sqrtf(sf->Ml[l]) * powf(
k1 * (k2 - k3 * cosf_fast(sf->w0 * (l+1))),
0.25f
);
if (w > 1.2f)
w = 1.2f;
else if (w < 0.5f)
w = 0.5f;
}
sf->Ml[l] *= w;
gamma += sf->Ml[l] * sf->Ml[l];
}
/* Compute final gamma and apply it */
gamma = sqrtf(rm0 / gamma);
for (l=0; l<sf->L; l++)
{
sf->Ml[l] *= gamma;
}
/* Update SE */
synth->SE = 0.95f * synth->SE + 0.05f * rm0;
if (synth->SE < 1e4f)
synth->SE = 1e4f;
}
/*! \brief Generate audio for a given subframe
* \param[in] synth Synthesizer state structure
* \param[out] audio Result buffer (180 samples)
* \param[in] sf Expanded subframe data for current subframe
* \param[in] sf_prev Expanded subframe data for prevous subframe
*/
void
ir77_ambe_synth_audio(struct ir77_ambe_synth *synth, int16_t *audio,
struct ir77_ambe_subframe *sf,
struct ir77_ambe_subframe *sf_prev)
{
float suv[180], sv[180];
int i;
ir77_ambe_synth_unvoiced(synth, suv, sf);
ir77_ambe_synth_voiced(synth, sv, sf, sf_prev);
for (i=0; i<180; i++)
audio[i] = (int16_t)((suv[i] + 2.0f * sv[i]) * 4.0f);
}
/*! @} */

1590
codec/tables.c Normal file

File diff suppressed because it is too large Load Diff

175
codec/tone.c Normal file
View File

@ -0,0 +1,175 @@
/* Iridium AMBE vocoder - Tone frames */
/* (C) 2015 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 Iridium 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[] = {
{ "0", 1336, 941 },
{ "1", 1209, 697 },
{ "2", 1336, 697 },
{ "3", 1477, 697 },
{ "4", 1209, 770 },
{ "5", 1336, 770 },
{ "6", 1477, 770 },
{ "7", 1209, 852 },
{ "8", 1336, 852 },
{ "9", 1477, 852 },
{ "A", 1633, 697 },
{ "B", 1633, 770 },
{ "C", 1633, 852 },
{ "D", 1633, 941 },
{ "#", 1477, 941 },
{ "*", 1209, 941 },
};
/*! \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 (as de-prioritized 103 ubits). Must be tone !
* \returns 0 for success. -EINVAL if frame was invalid.
*/
int
ir77_ambe_decode_tone(struct ir77_ambe_decoder *dec,
int16_t *audio, int N, const ubit_t *frame)
{
int p_log_ampl, p_freq;
int i, j, cnt;
int amplitude;
/* Decode parameters */
p_log_ampl =
(frame[10] << 7) |
(frame[11] << 6) |
(frame[12] << 5) |
(frame[15] << 4) |
(frame[16] << 3) |
(frame[17] << 2) |
(frame[18] << 1) |
(frame[19] << 0);
p_freq = 0;
for (i=0; i<8; i++) {
cnt = 0;
for (j=0; j<10; j++)
cnt += frame[20+(j<<3)+i];
p_freq = (p_freq << 1) | (cnt >= 5);
}
/* Clear audio */
memset(audio, 0x00, sizeof(int16_t) * N);
/* Compute amplitude */
amplitude = (int)(32767.0f * exp2f(((float)p_log_ampl-255.0f)/17.0f));
/* Interpret frequency code */
if (p_freq < 0x10)
{
/* DTMF tone */
int di = p_freq & 0xf;
tone_gen(audio, N, amplitude >> 1,
dtmf_tones[di].f1, &dec->tone_phase_f1);
tone_gen(audio, N, amplitude >> 1,
dtmf_tones[di].f2, &dec->tone_phase_f2);
}
else if ((p_freq >= 0x15) && (p_freq <= 0x8a))
{
int freq_hz = ((p_freq - 0x10) * 125) >> 2; /* 31.25 Hz increments */
tone_gen(audio, N, amplitude,
freq_hz, &dec->tone_phase_f1);
}
else if ((p_freq >= 0x90) && (p_freq <= 0x94))
{
/* Call progress tone */
int cpi = p_freq & 0xf;
tone_gen(audio, N, amplitude >> 1,
call_progress_tones[cpi].f1, &dec->tone_phase_f1);
tone_gen(audio, N, amplitude >> 1,
call_progress_tones[cpi].f2, &dec->tone_phase_f2);
}
else
{
/* Invalid */
return -EINVAL;
}
return 0;
}
/*! @} */