forked from satellite/osmo-ir77
codec: Import current codec code
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
This commit is contained in:
parent
30e476ab5f
commit
39141a86bb
|
@ -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)
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*! @} */
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*! @} */
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/*! @} */
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/*! @} */
|
|
@ -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__ */
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*! @} */
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
||||
|
||||
/*! @} */
|
Loading…
Reference in New Issue