diff options
-rw-r--r-- | codec/Makefile | 12 | ||||
-rw-r--r-- | codec/ambe.c | 176 | ||||
-rw-r--r-- | codec/ambe.h | 44 | ||||
-rw-r--r-- | codec/ecc.c | 270 | ||||
-rw-r--r-- | codec/ecc_tables.h | 571 | ||||
-rw-r--r-- | codec/frame.c | 483 | ||||
-rw-r--r-- | codec/ir77_ambe_decode.c | 199 | ||||
-rw-r--r-- | codec/math.c | 177 | ||||
-rw-r--r-- | codec/private.h | 178 | ||||
-rw-r--r-- | codec/synth.c | 381 | ||||
-rw-r--r-- | codec/tables.c | 1590 | ||||
-rw-r--r-- | codec/tone.c | 175 |
12 files changed, 4256 insertions, 0 deletions
diff --git a/codec/Makefile b/codec/Makefile new file mode 100644 index 0000000..4393d97 --- /dev/null +++ b/codec/Makefile @@ -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) diff --git a/codec/ambe.c b/codec/ambe.c new file mode 100644 index 0000000..705ffab --- /dev/null +++ b/codec/ambe.c @@ -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; +} + +/*! @} */ diff --git a/codec/ambe.h b/codec/ambe.h new file mode 100644 index 0000000..4784cf5 --- /dev/null +++ b/codec/ambe.h @@ -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__ */ diff --git a/codec/ecc.c b/codec/ecc.c new file mode 100644 index 0000000..d282a8a --- /dev/null +++ b/codec/ecc.c @@ -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; +} + +/*! @} */ diff --git a/codec/ecc_tables.h b/codec/ecc_tables.h new file mode 100644 index 0000000..724a571 --- /dev/null +++ b/codec/ecc_tables.h @@ -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__ */ diff --git a/codec/frame.c b/codec/frame.c new file mode 100644 index 0000000..7a3eb3e --- /dev/null +++ b/codec/frame.c @@ -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; + } +} + +/*! @} */ diff --git a/codec/ir77_ambe_decode.c b/codec/ir77_ambe_decode.c new file mode 100644 index 0000000..4d8fd7b --- /dev/null +++ b/codec/ir77_ambe_decode.c @@ -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; +} diff --git a/codec/math.c b/codec/math.c new file mode 100644 index 0000000..44a9e21 --- /dev/null +++ b/codec/math.c @@ -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; + } +} + +/*! @} */ diff --git a/codec/private.h b/codec/private.h new file mode 100644 index 0000000..b64252d --- /dev/null +++ b/codec/private.h @@ -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__ */ diff --git a/codec/synth.c b/codec/synth.c new file mode 100644 index 0000000..69ce9ff --- /dev/null +++ b/codec/synth.c @@ -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); +} + +/*! @} */ diff --git a/codec/tables.c b/codec/tables.c new file mode 100644 index 0000000..512d59f --- /dev/null +++ b/codec/tables.c @@ -0,0 +1,1590 @@ +/* Iridium AMBE vocoder - 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/>. + */ + +/*! \addtogroup codec_private + * @{ + */ + +/*! \file codec/tables.c + * \brief Iridium AMBE vocoder tables + */ + +#include <stdint.h> + +/*! \brief Bit prioritization table */ +const struct { + uint8_t pos; + uint8_t len; +} ir77_ambe_prio_tbl[] = { + { 0, 6 }, + { 10, 3 }, + { 15, 3 }, + { 28, 8 }, + { 36, 6 }, + { 49, 8 }, + { 63, 7 }, + { 73, 7 }, + { 20, 2 }, + { 24, 2 }, + { 42, 7 }, + { 13, 1 }, + { 83, 4 }, + { 93, 4 }, + { 6, 4 }, + { 14, 1 }, + { 18, 2 }, + { 87, 3 }, + { 97, 3 }, + { 57, 6 }, + { 70, 3 }, + { 80, 3 }, + { 90, 3 }, + { 100, 3 }, + { 22, 2 }, + { 26, 2 }, + { 0, 0 }, /* Termination */ +}; + +/*! \brief f0log/pitch difference vector quantization table */ +const float ir77_ambe_pitch_diff_vq[64][2] = { + { -0.9111f, 0.8867f }, + { -0.7461f, 0.8027f }, + { -0.7188f, 0.6191f }, + { -0.5527f, 0.6084f }, + { -0.5635f, 0.4619f }, + { -0.3809f, 0.4971f }, + { -0.4189f, 0.4209f }, + { -0.3809f, 0.2744f }, + { -0.2324f, 0.3340f }, + { -0.2490f, 0.2051f }, + { -0.1357f, 0.2393f }, + { -0.2217f, 0.1006f }, + { -0.0566f, 0.1670f }, + { -0.1289f, 0.0898f }, + { -0.1357f, 0.0029f }, + { -0.0498f, 0.0898f }, + { 0.0088f, 0.1211f }, + { -0.0576f, 0.0322f }, + { -0.0723f, -0.0117f }, + { 0.0146f, 0.0664f }, + { 0.0498f, 0.0996f }, + { -0.0898f, -0.0469f }, + { -0.0107f, 0.0342f }, + { -0.0283f, -0.0088f }, + { -0.0400f, -0.0420f }, + { 0.0000f, 0.0000f }, + { 0.0576f, 0.0557f }, + { -0.0732f, -0.0762f }, + { 0.0313f, 0.0254f }, + { 0.0840f, 0.0801f }, + { 0.0166f, -0.0137f }, + { -0.0381f, -0.0762f }, + { -0.0020f, -0.0508f }, + { 0.0986f, 0.0449f }, + { 0.0674f, 0.0098f }, + { -0.0498f, -0.1094f }, + { 0.0420f, -0.0254f }, + { -0.0010f, -0.0869f }, + { 0.1211f, 0.0107f }, + { 0.0371f, -0.0771f }, + { -0.0098f, -0.1299f }, + { 0.0977f, -0.0381f }, + { 0.0615f, -0.1328f }, + { 0.1748f, -0.0410f }, + { 0.1260f, -0.1182f }, + { 0.0596f, -0.2080f }, + { 0.2305f, -0.1152f }, + { 0.1357f, -0.2100f }, + { 0.2256f, -0.2383f }, + { 0.2949f, -0.2021f }, + { 0.3711f, -0.2314f }, + { 0.2480f, -0.3701f }, + { 0.3652f, -0.3994f }, + { 0.4443f, -0.3740f }, + { 0.4316f, -0.5420f }, + { 0.5410f, -0.4580f }, + { 0.5410f, -0.5791f }, + { 0.7012f, -0.5859f }, + { 0.5977f, -0.7402f }, + { 0.7139f, -0.7588f }, + { 0.8369f, -0.7471f }, + { 0.8369f, -0.9160f }, + { 0.9873f, -0.9453f }, + { 1.0732f, -1.1279f }, +}; + +/*! \brief Number of harmonics per group for a given L (starts at L=9) */ +const uint8_t ir77_ambe_hpg_tbl[48][4] = { + { 2, 2, 2, 3 }, /* L = 9 */ + { 2, 2, 3, 3 }, + { 2, 3, 3, 3 }, + { 2, 3, 3, 4 }, + { 3, 3, 3, 4 }, + { 3, 3, 4, 4 }, + { 3, 3, 4, 5 }, + { 3, 4, 4, 5 }, + { 3, 4, 5, 5 }, + { 4, 4, 5, 5 }, + { 4, 4, 5, 6 }, + { 4, 4, 6, 6 }, + { 4, 5, 6, 6 }, + { 4, 5, 6, 7 }, + { 5, 5, 6, 7 }, + { 5, 5, 7, 7 }, + { 5, 6, 7, 7 }, + { 5, 6, 7, 8 }, + { 5, 6, 8, 8 }, + { 6, 6, 8, 8 }, + { 6, 6, 8, 9 }, + { 6, 7, 8, 9 }, + { 6, 7, 9, 9 }, + { 6, 7, 9, 10 }, + { 7, 7, 9, 10 }, + { 7, 8, 9, 10 }, + { 7, 8, 10, 10 }, + { 7, 8, 10, 11 }, + { 8, 8, 10, 11 }, + { 8, 9, 10, 11 }, + { 8, 9, 11, 11 }, + { 8, 9, 11, 12 }, + { 8, 9, 11, 13 }, + { 8, 9, 12, 13 }, + { 8, 10, 12, 13 }, + { 9, 10, 12, 13 }, + { 9, 10, 12, 14 }, + { 9, 10, 13, 14 }, + { 9, 11, 13, 14 }, + { 10, 11, 13, 14 }, + { 10, 11, 13, 15 }, + { 10, 11, 14, 15 }, + { 10, 12, 14, 15 }, + { 10, 12, 14, 16 }, + { 11, 12, 14, 16 }, + { 11, 12, 15, 16 }, + { 11, 12, 15, 17 }, + { 11, 13, 15, 17 }, /* L = 56 */ +}; + +/*! \brief Gain difference (in dual-subframe quant) vector quantization table */ +const float ir77_ambe_gain_diff_vq[32][2] = { + { -3.2695f, 3.2710f }, + { -2.7949f, 2.7544f }, + { -2.3730f, 2.3701f }, + { -1.8853f, 1.8672f }, + { -1.5293f, 1.5093f }, + { -1.2393f, 1.2842f }, + { -1.0020f, 1.0195f }, + { -0.9229f, 0.7280f }, + { -0.6196f, 0.7944f }, + { -0.6592f, 0.4897f }, + { -0.3691f, 0.5425f }, + { -0.4219f, 0.2510f }, + { -0.1582f, 0.3042f }, + { -0.2373f, 0.0791f }, + { -0.1450f, -0.0532f }, + { 0.0264f, 0.1851f }, + { 0.0103f, -0.0239f }, + { 0.1592f, 0.0596f }, + { 0.0103f, -0.2153f }, + { 0.2549f, -0.0957f }, + { 0.1699f, -0.3350f }, + { 0.4033f, -0.2275f }, + { 0.3076f, -0.4907f }, + { 0.4883f, -0.6460f }, + { 0.5732f, -0.3950f }, + { 0.7964f, -0.6221f }, + { 0.7222f, -0.8735f }, + { 1.0195f, -0.9570f }, + { 1.2529f, -1.2324f }, + { 1.5293f, -1.5552f }, + { 1.9326f, -1.9502f }, + { 2.7080f, -2.9189f }, +}; + +/*! \brief V/UV decisions (MSBs = low freq) */ +const uint8_t ir77_ambe_v_uv_tbl[16] = { + 0x00, 0x80, 0xc0, 0xc1, 0xe0, 0xe1, 0xf0, 0xf1, + 0xf9, 0xf8, 0xfb, 0xdf, 0xfc, 0xfe, 0xfd, 0xff, +}; + +/*! \brief PRBA[1:2] Sum vector quantization table */ +const float ir77_ambe_prba_sum12_vq[256][2] = { + { 0.1758f, -0.1240f }, + { -0.2070f, -0.1523f }, + { 0.5034f, -0.0322f }, + { 0.1270f, 0.0137f }, + { -0.1704f, -0.2300f }, + { -0.7412f, -0.3330f }, + { 0.1211f, -0.0293f }, + { -0.2129f, -0.0063f }, + { -0.0186f, 0.0195f }, + { -0.5044f, 0.1113f }, + { 0.2544f, 0.1719f }, + { -0.0552f, 0.2490f }, + { -0.5107f, 0.0024f }, + { -1.0205f, 0.1919f }, + { -0.0796f, 0.1401f }, + { -0.5410f, 0.3867f }, + { 0.2827f, 0.0679f }, + { -0.0210f, 0.1226f }, + { 0.6826f, 0.3813f }, + { 0.2207f, 0.3008f }, + { -0.0483f, 0.0762f }, + { -0.4487f, 0.2202f }, + { 0.2134f, 0.2373f }, + { -0.1177f, 0.4199f }, + { 0.0825f, 0.2544f }, + { -0.2207f, 0.3560f }, + { 0.4067f, 0.5469f }, + { 0.1172f, 0.5298f }, + { -0.4004f, 0.4961f }, + { -1.0483f, 0.5596f }, + { -0.0210f, 0.6274f }, + { -0.2207f, 1.1494f }, + { 0.4546f, -0.4072f }, + { 0.1714f, -0.1772f }, + { 1.0742f, -0.2739f }, + { 0.4678f, -0.0869f }, + { 0.1055f, -0.3828f }, + { -0.2705f, -0.4189f }, + { 0.4087f, -0.1372f }, + { 0.0791f, -0.1011f }, + { 0.2173f, -0.0908f }, + { -0.0464f, -0.0303f }, + { 0.5601f, 0.0742f }, + { 0.1978f, 0.0864f }, + { -0.0659f, -0.0889f }, + { -0.5801f, -0.1108f }, + { 0.1909f, 0.0381f }, + { -0.1055f, 0.0845f }, + { 0.6553f, -0.0361f }, + { 0.2363f, 0.0181f }, + { 1.0098f, 0.1489f }, + { 0.6123f, 0.1577f }, + { 0.2417f, -0.0249f }, + { -0.1021f, -0.0361f }, + { 0.4727f, 0.1035f }, + { 0.1665f, 0.1128f }, + { 0.3706f, 0.1938f }, + { 0.0806f, 0.1577f }, + { 0.6768f, 0.5283f }, + { 0.3599f, 0.4219f }, + { 0.0322f, 0.2168f }, + { -0.3438f, 0.3452f }, + { 0.3115f, 0.3115f }, + { -0.0054f, 0.4561f }, + { 0.4946f, -0.1411f }, + { 0.2036f, -0.0498f }, + { 0.8926f, -0.0313f }, + { 0.4219f, 0.0767f }, + { 0.1646f, -0.0830f }, + { -0.1411f, -0.0977f }, + { 0.4121f, 0.0186f }, + { 0.1211f, 0.0913f }, + { 0.2954f, 0.1079f }, + { 0.0239f, 0.1553f }, + { 0.5430f, 0.2241f }, + { 0.2568f, 0.3794f }, + { 0.0044f, 0.0664f }, + { -0.3301f, 0.1909f }, + { 0.2666f, 0.2324f }, + { -0.0439f, 0.3486f }, + { 0.7178f, 0.2471f }, + { 0.3057f, 0.2007f }, + { 1.1772f, 0.3525f }, + { 0.5415f, 0.4644f }, + { 0.2524f, 0.1187f }, + { -0.0239f, 0.1909f }, + { 0.5532f, 0.3457f }, + { 0.2524f, 0.4941f }, + { 0.4590f, 0.3853f }, + { 0.1113f, 0.4219f }, + { 1.1128f, 0.9194f }, + { 0.4648f, 0.9521f }, + { 0.0581f, 0.3560f }, + { -0.3066f, 0.7578f }, + { 0.5234f, 0.6426f }, + { 0.0171f, 0.8335f }, + { 0.9063f, -0.4927f }, + { 0.4883f, -0.2866f }, + { 1.7275f, -0.2300f }, + { 1.0479f, -0.0308f }, + { 0.4458f, -0.2134f }, + { 0.1274f, -0.1304f }, + { 0.8921f, -0.2202f }, + { 0.4248f, -0.0273f }, + { 0.5732f, -0.0073f }, + { 0.2832f, 0.0259f }, + { 0.9771f, 0.3452f }, + { 0.4741f, 0.1924f }, + { 0.1982f, -0.0073f }, + { -0.0566f, 0.0225f }, + { 0.5308f, 0.1426f }, + { 0.1841f, 0.1792f }, + { 1.4692f, 0.1084f }, + { 0.7202f, 0.1387f }, + { 1.8579f, 0.2144f }, + { 1.4692f, 0.4258f }, + { 0.6553f, 0.0542f }, + { 0.2373f, 0.0630f }, + { 1.2026f, 0.1235f }, + { 0.6118f, 0.2656f }, + { 0.8711f, 0.5254f }, + { 0.3887f, 0.3262f }, + { 1.5845f, 0.8184f }, + { 0.7993f, 0.7397f }, + { 0.3599f, 0.2563f }, + { 0.0288f, 0.2900f }, + { 1.1089f, 0.5947f }, + { 0.2661f, 0.6797f }, + { 0.0000f, -0.4746f }, + { -0.6055f, -0.4746f }, + { 0.2271f, -0.2246f }, + { -0.0908f, -0.2759f }, + { -0.3105f, -0.7300f }, + { -1.0898f, -0.7383f }, + { -0.1665f, -0.3325f }, + { -0.6963f, -0.6392f }, + { -0.3711f, -0.2617f }, + { -0.9312f, -0.2646f }, + { 0.0527f, -0.0264f }, + { -0.3784f, -0.0347f }, + { -1.2490f, -0.3608f }, + { -1.6650f, -0.2192f }, + { -0.4771f, -0.0972f }, + { -1.2339f, -0.0688f }, + { 0.0791f, -0.1548f }, + { -0.2896f, -0.1143f }, + { 0.3613f, -0.0171f }, + { 0.0645f, 0.0635f }, + { -0.2827f, -0.1880f }, + { -0.7744f, -0.1377f }, + { 0.0068f, -0.0239f }, + { -0.3115f, 0.0737f }, + { -0.1597f, 0.1206f }, + { -0.6079f, 0.2114f }, + { 0.1514f, 0.2349f }, + { -0.1377f, 0.2886f }, + { -0.7959f, 0.1172f }, + { -1.4468f, 0.2446f }, + { -0.2681f, 0.2515f }, + { -0.6802f, 0.6611f }, + { 0.2607f, -0.7041f }, + { 0.0327f, -0.6387f }, + { 0.5161f, -0.5391f }, + { 0.2495f, -0.2993f }, + { -0.0396f, -0.8564f }, + { -0.5337f, -0.9341f }, + { 0.1938f, -0.3677f }, + { -0.1504f, -0.4458f }, + { 0.0996f, -0.2900f }, + { -0.3613f, -0.3833f }, + { 0.3105f, -0.1499f }, + { -0.0337f, -0.1528f }, + { -0.3950f, -0.5513f }, + { -0.8667f, -0.4736f }, + { -0.0728f, -0.2061f }, + { -0.6001f, -0.2588f }, + { 0.3052f, -0.2334f }, + { 0.0190f, -0.1802f }, + { 0.5674f, -0.1064f }, + { 0.2954f, -0.0176f }, + { 0.0190f, -0.3257f }, + { -0.2622f, -0.2900f }, + { 0.2715f, -0.1104f }, + { 0.0386f, -0.0684f }, + { 0.1646f, -0.0327f }, + { -0.1509f, 0.0356f }, + { 0.3687f, 0.1226f }, + { 0.1357f, 0.1450f }, + { -0.1606f, -0.0366f }, + { -0.6406f, 0.0317f }, + { 0.1064f, 0.0508f }, + { -0.2524f, 0.1470f }, + { 0.3076f, -0.3652f }, + { -0.0127f, -0.2559f }, + { 0.5674f, -0.2183f }, + { 0.2593f, -0.1772f }, + { -0.0728f, -0.3652f }, + { -0.5020f, -0.3599f }, + { 0.2173f, -0.1421f }, + { -0.1211f, -0.1494f }, + { 0.1206f, -0.0752f }, + { -0.2178f, -0.0825f }, + { 0.3682f, 0.0386f }, + { 0.0903f, 0.1055f }, + { -0.3750f, -0.1440f }, + { -0.9429f, -0.0474f }, + { 0.0420f, 0.0200f }, + { -0.3994f, 0.0850f }, + { 0.3906f, -0.0649f }, + { 0.0894f, 0.0044f }, + { 0.8457f, 0.1577f }, + { 0.3140f, 0.1484f }, + { 0.0830f, -0.0513f }, + { -0.2886f, -0.0234f }, + { 0.3394f, 0.0811f }, + { 0.0381f, 0.1064f }, + { 0.2114f, 0.1411f }, + { -0.1025f, 0.1948f }, + { 0.4805f, 0.2852f }, + { 0.1602f, 0.3687f }, + { -0.1733f, 0.1948f }, + { -0.7690f, 0.3433f }, + { 0.1343f, 0.3013f }, + { -0.2310f, 0.5215f }, + { 0.6050f, -0.7075f }, + { 0.3267f, -0.4951f }, + { 1.3008f, -0.4463f }, + { 0.6958f, -0.4771f }, + { 0.1597f, -0.5156f }, + { -0.1743f, -0.5640f }, + { 0.5913f, -0.3438f }, + { 0.1597f, -0.2539f }, + { 0.3896f, -0.2974f }, + { 0.1113f, -0.2002f }, + { 0.6606f, -0.1616f }, + { 0.3198f, -0.0669f }, + { 0.0483f, -0.2310f }, + { -0.4453f, -0.2080f }, + { 0.2642f, -0.0645f }, + { -0.0073f, -0.0747f }, + { 0.7197f, -0.2764f }, + { 0.3511f, -0.1099f }, + { 1.2910f, -0.1123f }, + { 0.7676f, 0.0303f }, + { 0.3687f, -0.1958f }, + { 0.0234f, -0.1172f }, + { 0.7617f, -0.1240f }, + { 0.3213f, 0.0303f }, + { 0.4761f, 0.0352f }, + { 0.1543f, 0.0615f }, + { 0.8208f, 0.3232f }, + { 0.4224f, 0.2378f }, + { 0.1606f, 0.0112f }, + { -0.1904f, 0.0664f }, + { 0.4165f, 0.1494f }, + { 0.1187f, 0.1948f }, +}; + +/*! \brief PRBA[3:4] Sum vector quantization table */ +const float ir77_ambe_prba_sum34_vq[64][2] = { + { 0.7690f, 0.1548f }, + { 0.3657f, 0.2974f }, + { 0.4819f, -0.1167f }, + { 0.2837f, 0.0547f }, + { 0.5605f, 0.3843f }, + { 0.2563f, 0.4556f }, + { 0.3315f, 0.1514f }, + { 0.0171f, 0.1743f }, + { 0.6904f, -0.1558f }, + { 0.3452f, -0.0488f }, + { 0.4956f, -0.3496f }, + { 0.2017f, -0.2012f }, + { 0.4170f, 0.0449f }, + { 0.2085f, 0.1289f }, + { 0.2598f, -0.1104f }, + { -0.0957f, -0.0425f }, + { 0.4995f, 0.1812f }, + { 0.1172f, 0.2080f }, + { 0.2231f, -0.0186f }, + { -0.0493f, 0.0181f }, + { 0.1245f, 0.3232f }, + { -0.0117f, 0.4590f }, + { 0.0073f, 0.0815f }, + { -0.1665f, 0.2837f }, + { 0.3633f, -0.1968f }, + { 0.0640f, -0.0786f }, + { 0.1094f, -0.2900f }, + { -0.1592f, -0.2900f }, + { 0.0791f, 0.0513f }, + { -0.0723f, 0.0996f }, + { -0.0078f, -0.1392f }, + { -0.4541f, -0.0605f }, + { 0.5718f, 0.0234f }, + { 0.0967f, 0.1221f }, + { 0.1611f, -0.0962f }, + { -0.0205f, -0.0601f }, + { 0.2334f, 0.2417f }, + { -0.0122f, 0.2778f }, + { 0.0322f, -0.0034f }, + { -0.3062f, 0.1792f }, + { 0.2817f, -0.3203f }, + { 0.0967f, -0.1621f }, + { 0.1450f, -0.4668f }, + { -0.0322f, -0.3652f }, + { 0.1206f, -0.0156f }, + { -0.1450f, 0.0322f }, + { -0.0806f, -0.2246f }, + { -0.4351f, -0.2217f }, + { 0.1660f, 0.0557f }, + { -0.1880f, 0.1260f }, + { -0.0991f, -0.1270f }, + { -0.3154f, -0.1235f }, + { -0.0889f, 0.1855f }, + { -0.3115f, 0.4067f }, + { -0.2407f, -0.0005f }, + { -0.5278f, 0.1504f }, + { 0.0244f, -0.2319f }, + { -0.2021f, -0.1865f }, + { -0.2124f, -0.4775f }, + { -0.5098f, -0.4111f }, + { -0.1880f, -0.0845f }, + { -0.3506f, 0.0313f }, + { -0.3081f, -0.2881f }, + { -0.7222f, -0.1060f }, +}; + +/*! \brief PRBA[5:7] Sum vector quantization table */ +const float ir77_ambe_prba_sum57_vq[128][3] = { + { -0.0352f, -0.0244f, -0.1870f }, + { -0.1187f, -0.0645f, -0.2529f }, + { 0.0903f, -0.0566f, -0.0991f }, + { 0.0205f, -0.0483f, -0.1104f }, + { -0.2021f, -0.0806f, -0.1431f }, + { -0.2993f, -0.1128f, -0.1104f }, + { -0.0562f, -0.0083f, 0.0215f }, + { -0.0840f, -0.0645f, -0.0005f }, + { -0.0142f, 0.1045f, -0.1543f }, + { 0.0137f, 0.0400f, -0.1211f }, + { 0.1387f, 0.0806f, -0.0332f }, + { 0.1182f, 0.0322f, -0.0884f }, + { -0.1396f, 0.1289f, -0.0552f }, + { -0.1675f, 0.0322f, -0.0444f }, + { 0.0205f, 0.1128f, 0.0767f }, + { -0.0073f, 0.0483f, 0.0435f }, + { -0.1235f, 0.1519f, -0.1816f }, + { -0.1157f, 0.0474f, -0.1377f }, + { 0.0610f, 0.1235f, -0.0825f }, + { 0.0303f, 0.0664f, -0.0386f }, + { -0.2539f, 0.0757f, -0.1484f }, + { -0.3154f, 0.0947f, -0.0278f }, + { -0.0850f, 0.1328f, 0.0601f }, + { -0.1001f, 0.0474f, 0.0601f }, + { 0.0381f, 0.2568f, -0.1924f }, + { -0.0313f, 0.1899f, -0.0605f }, + { 0.1611f, 0.3423f, -0.0278f }, + { 0.1074f, 0.2188f, -0.0386f }, + { -0.1157f, 0.3042f, -0.0605f }, + { -0.1924f, 0.2378f, 0.0493f }, + { 0.0229f, 0.2949f, 0.1479f }, + { -0.0156f, 0.2188f, 0.0601f }, + { 0.0723f, -0.1597f, -0.2695f }, + { 0.0562f, -0.1313f, -0.1738f }, + { 0.2573f, -0.1807f, -0.1860f }, + { 0.2495f, -0.1240f, -0.0542f }, + { -0.0649f, -0.0957f, -0.1260f }, + { -0.1211f, -0.1665f, -0.0903f }, + { 0.0400f, -0.0674f, -0.0186f }, + { 0.0400f, -0.1382f, -0.0063f }, + { 0.2334f, -0.0039f, -0.2339f }, + { 0.1768f, -0.0674f, -0.1382f }, + { 0.3784f, -0.0107f, -0.1260f }, + { 0.3140f, 0.0034f, 0.0054f }, + { 0.0479f, 0.0034f, -0.0542f }, + { -0.0005f, 0.0103f, -0.0186f }, + { 0.2012f, 0.0317f, 0.0415f }, + { 0.1123f, -0.0107f, 0.1011f }, + { 0.0703f, 0.0977f, -0.2432f }, + { 0.0845f, 0.0039f, -0.1934f }, + { 0.2476f, 0.0635f, -0.0688f }, + { 0.2051f, -0.0132f, -0.0439f }, + { -0.0498f, 0.0039f, -0.0815f }, + { -0.0781f, 0.0039f, -0.0317f }, + { 0.0776f, 0.0552f, 0.0181f }, + { 0.0493f, 0.0039f, 0.0308f }, + { 0.2402f, 0.2090f, -0.1685f }, + { 0.1694f, 0.1064f, -0.1313f }, + { 0.3608f, 0.2002f, -0.0068f }, + { 0.2192f, 0.1489f, 0.0181f }, + { 0.0845f, 0.1489f, 0.0181f }, + { -0.0005f, 0.1318f, 0.0059f }, + { 0.1978f, 0.2432f, 0.1426f }, + { 0.0986f, 0.1577f, 0.1426f }, + { -0.0684f, -0.1797f, -0.1621f }, + { -0.1973f, -0.2529f, -0.1621f }, + { 0.0298f, -0.2310f, 0.0122f }, + { -0.0459f, -0.1870f, 0.0122f }, + { -0.2349f, -0.2017f, -0.0127f }, + { -0.3711f, -0.2456f, -0.0376f }, + { -0.1367f, -0.2017f, 0.0991f }, + { -0.2651f, -0.2603f, 0.1489f }, + { -0.0308f, -0.0479f, -0.0503f }, + { -0.0459f, -0.1138f, -0.0503f }, + { 0.0981f, -0.0698f, 0.0371f }, + { 0.0449f, -0.0845f, 0.0620f }, + { -0.1440f, -0.0332f, 0.0244f }, + { -0.2046f, -0.1064f, 0.0742f }, + { -0.0762f, -0.0405f, 0.1616f }, + { -0.1138f, -0.1357f, 0.2114f }, + { -0.1118f, -0.0513f, -0.0820f }, + { -0.1714f, -0.0854f, -0.0410f }, + { -0.0005f, -0.0376f, 0.0308f }, + { -0.0522f, -0.0444f, 0.0718f }, + { -0.2534f, -0.0376f, 0.0000f }, + { -0.3203f, -0.0786f, 0.1128f }, + { -0.1567f, -0.0239f, 0.1128f }, + { -0.2012f, -0.0171f, 0.2256f }, + { -0.0522f, 0.0854f, -0.0718f }, + { -0.0674f, 0.0649f, -0.0103f }, + { 0.1411f, 0.0854f, 0.0923f }, + { 0.0591f, 0.0513f, 0.1025f }, + { -0.1865f, 0.0649f, 0.0513f }, + { -0.2759f, 0.0991f, 0.1436f }, + { -0.0078f, 0.1196f, 0.1948f }, + { -0.1196f, 0.0786f, 0.1743f }, + { 0.0732f, -0.2876f, -0.1118f }, + { -0.0332f, -0.3340f, -0.2012f }, + { 0.2451f, -0.2876f, -0.0225f }, + { 0.1060f, -0.3525f, 0.0669f }, + { -0.0903f, -0.2783f, -0.0225f }, + { -0.1719f, -0.3804f, 0.0220f }, + { 0.0649f, -0.2134f, 0.1265f }, + { -0.0410f, -0.2876f, 0.1563f }, + { 0.1226f, -0.1021f, -0.0376f }, + { 0.1226f, -0.1855f, -0.0674f }, + { 0.3350f, -0.1299f, 0.0815f }, + { 0.2124f, -0.1855f, 0.1113f }, + { -0.0249f, -0.1021f, 0.0371f }, + { 0.0078f, -0.1577f, 0.0669f }, + { 0.1226f, -0.1021f, 0.1411f }, + { 0.0898f, -0.1577f, 0.2603f }, + { 0.0273f, -0.1265f, -0.0791f }, + { -0.0137f, -0.1987f, -0.0791f }, + { 0.1846f, -0.0723f, 0.0469f }, + { 0.1299f, -0.1626f, 0.0361f }, + { -0.0957f, -0.1177f, 0.0679f }, + { -0.1230f, -0.1538f, 0.0049f }, + { 0.0205f, -0.0903f, 0.1411f }, + { -0.0410f, -0.1265f, 0.1309f }, + { 0.1299f, 0.0088f, 0.0151f }, + { 0.1025f, -0.0273f, -0.0269f }, + { 0.3076f, 0.0811f, 0.1621f }, + { 0.2188f, -0.0273f, 0.1411f }, + { 0.0205f, -0.0093f, 0.1099f }, + { -0.0410f, 0.0361f, 0.1099f }, + { 0.1299f, 0.0449f, 0.2358f }, + { 0.0205f, -0.0093f, 0.2358f }, +}; + +/*! \brief PRBA[1:3] Difference vector quantization table */ +const float ir77_ambe_prba_dif13_vq[256][3] = { + { -0.0952f, 0.0181f, 0.0547f }, + { -0.2441f, -0.0371f, 0.0547f }, + { -0.2983f, -0.1104f, 0.1401f }, + { -0.6504f, -0.2017f, 0.0303f }, + { -0.2036f, 0.0181f, -0.1162f }, + { -0.4746f, 0.0361f, -0.1650f }, + { -0.5962f, -0.0552f, -0.0918f }, + { -0.8130f, -0.2017f, -0.1650f }, + { 0.0269f, -0.0552f, 0.0059f }, + { -0.1357f, -0.0918f, -0.0430f }, + { -0.0815f, -0.2202f, 0.0791f }, + { -0.3252f, -0.2568f, -0.0430f }, + { -0.0679f, -0.0552f, -0.0796f }, + { -0.2983f, -0.1470f, -0.2383f }, + { -0.3389f, -0.2935f, -0.1772f }, + { -0.5830f, -0.5313f, -0.2139f }, + { -0.0640f, 0.1646f, 0.0581f }, + { -0.1914f, 0.1523f, 0.0400f }, + { -0.1489f, 0.0791f, 0.0674f }, + { -0.4995f, 0.0791f, 0.0220f }, + { -0.1382f, 0.1768f, -0.0591f }, + { -0.3823f, 0.2622f, -0.1494f }, + { -0.3506f, 0.1279f, -0.0591f }, + { -0.5947f, 0.1890f, -0.1313f }, + { 0.0635f, 0.0303f, 0.0132f }, + { -0.0215f, 0.0059f, -0.0229f }, + { -0.0107f, -0.0308f, 0.0400f }, + { -0.1807f, -0.0552f, -0.0049f }, + { 0.0210f, 0.0547f, -0.0771f }, + { -0.1489f, 0.0791f, -0.1855f }, + { -0.1274f, -0.0063f, -0.0684f }, + { -0.4146f, -0.1040f, -0.2036f }, + { 0.0640f, 0.0166f, -0.0391f }, + { -0.0771f, 0.0166f, -0.0498f }, + { -0.0771f, -0.0845f, 0.0049f }, + { -0.2949f, -0.1743f, -0.1157f }, + { -0.0259f, 0.0391f, -0.0718f }, + { -0.3081f, 0.0391f, -0.1709f }, + { -0.2695f, -0.0845f, -0.1489f }, + { -0.6025f, -0.1294f, -0.3354f }, + { 0.1919f, -0.0620f, -0.0718f }, + { -0.0005f, -0.0732f, -0.1050f }, + { 0.1152f, -0.1631f, -0.0278f }, + { -0.1924f, -0.2305f, -0.0938f }, + { 0.0640f, -0.0508f, -0.1270f }, + { -0.0898f, -0.1743f, -0.2915f }, + { -0.0645f, -0.1069f, -0.1377f }, + { -0.4106f, -0.2979f, -0.3354f }, + { 0.1538f, 0.1621f, -0.0771f }, + { -0.0122f, 0.1157f, -0.0659f }, + { -0.0239f, 0.0415f, 0.0107f }, + { -0.1304f, 0.0693f, -0.0771f }, + { -0.0356f, 0.2085f, -0.1318f }, + { -0.2251f, 0.1714f, -0.1978f }, + { -0.0596f, 0.1250f, -0.1099f }, + { -0.2251f, -0.0049f, -0.3296f }, + { 0.5088f, 0.1343f, -0.0991f }, + { 0.0942f, 0.0415f, -0.1099f }, + { 0.1416f, -0.0234f, -0.0332f }, + { -0.0239f, -0.0234f, -0.0659f }, + { 0.2363f, 0.0415f, -0.2856f }, + { -0.0239f, 0.0322f, -0.2856f }, + { 0.1299f, -0.0049f, -0.1978f }, + { -0.1777f, -0.0698f, -0.2090f }, + { 0.0327f, -0.0645f, 0.0557f }, + { -0.0991f, -0.1289f, 0.0557f }, + { -0.0552f, -0.1450f, 0.1528f }, + { -0.3955f, -0.2900f, 0.1670f }, + { -0.0659f, -0.0483f, -0.0278f }, + { -0.2310f, -0.0806f, -0.0698f }, + { -0.3076f, -0.1450f, 0.0000f }, + { -0.5054f, -0.2739f, -0.1113f }, + { 0.1758f, -0.2095f, 0.0557f }, + { 0.0439f, -0.2095f, 0.0000f }, + { 0.0547f, -0.3545f, 0.0835f }, + { -0.2090f, -0.4028f, -0.0420f }, + { 0.0767f, -0.0967f, -0.0835f }, + { -0.0771f, -0.2256f, -0.1533f }, + { -0.0659f, -0.2900f, -0.0142f }, + { -0.2417f, -0.5317f, -0.2505f }, + { 0.1348f, 0.0659f, 0.1279f }, + { -0.0391f, 0.0132f, 0.0337f }, + { 0.0190f, -0.0132f, 0.0767f }, + { -0.1353f, -0.0483f, 0.0679f }, + { 0.0288f, 0.0659f, -0.0259f }, + { -0.2222f, 0.1011f, -0.0688f }, + { -0.0581f, 0.0044f, -0.0088f }, + { -0.3184f, -0.0220f, -0.0771f }, + { 0.2891f, -0.0308f, -0.0347f }, + { 0.0767f, -0.0659f, -0.0005f }, + { 0.0576f, -0.1099f, 0.0425f }, + { -0.0391f, -0.1626f, -0.0176f }, + { 0.2217f, 0.0044f, -0.1113f }, + { 0.0288f, -0.0044f, -0.0859f }, + { -0.0098f, -0.1099f, -0.0518f }, + { -0.1548f, -0.1450f, -0.1284f }, + { 0.2119f, -0.0366f, 0.0127f }, + { 0.0381f, -0.0610f, -0.0522f }, + { 0.0576f, -0.1221f, -0.0132f }, + { -0.1162f, -0.1831f, -0.0264f }, + { 0.0864f, -0.0244f, -0.0522f }, + { -0.0581f, -0.0366f, -0.1816f }, + { -0.0776f, -0.1221f, -0.0649f }, + { -0.2026f, -0.2441f, -0.2334f }, + { 0.3950f, -0.2686f, -0.1040f }, + { 0.1445f, -0.1587f, -0.1167f }, + { 0.1924f, -0.2686f, -0.0522f }, + { -0.0005f, -0.4028f, -0.1558f }, + { 0.2407f, -0.2319f, -0.2202f }, + { 0.0962f, -0.1343f, -0.3110f }, + { 0.0767f, -0.2686f, -0.1816f }, + { 0.0288f, -0.3784f, -0.3755f }, + { 0.4521f, 0.1436f, 0.0801f }, + { 0.0879f, 0.0601f, -0.0103f }, + { 0.1504f, 0.0137f, 0.0200f }, + { -0.0005f, -0.0142f, 0.0000f }, + { 0.1758f, 0.0972f, -0.1304f }, + { 0.0122f, 0.1064f, -0.1304f }, + { 0.0122f, 0.0229f, -0.0400f }, + { -0.0630f, 0.0322f, -0.1201f }, + { 0.7163f, -0.0513f, -0.0400f }, + { 0.3140f, 0.0601f, -0.1001f }, + { 0.2510f, -0.1348f, -0.0703f }, + { 0.1255f, -0.0884f, -0.0400f }, + { 0.5151f, -0.0327f, -0.2202f }, + { 0.3140f, -0.0698f, -0.1904f }, + { 0.1504f, -0.0791f, -0.1504f }, + { 0.0249f, -0.1162f, -0.1802f }, + { 0.0000f, 0.0762f, 0.1948f }, + { -0.1685f, 0.0923f, 0.1831f }, + { -0.0986f, -0.0044f, 0.2637f }, + { -0.4917f, 0.0278f, 0.2061f }, + { -0.1123f, 0.1162f, 0.0225f }, + { -0.3369f, 0.1084f, 0.0571f }, + { -0.3511f, 0.0117f, 0.1372f }, + { -0.7300f, 0.0679f, 0.0913f }, + { 0.1401f, -0.0288f, 0.0913f }, + { -0.0562f, -0.0127f, 0.0801f }, + { 0.0000f, -0.0366f, 0.1719f }, + { -0.1826f, -0.1172f, 0.1260f }, + { 0.0137f, 0.0195f, -0.0005f }, + { -0.1548f, 0.0278f, -0.0234f }, + { -0.1968f, -0.1333f, -0.0005f }, + { -0.4355f, -0.1333f, -0.0806f }, + { 0.0513f, 0.3936f, 0.2974f }, + { -0.0308f, 0.2158f, 0.1641f }, + { -0.0410f, 0.1650f, 0.2974f }, + { -0.2871f, 0.1143f, 0.2256f }, + { 0.0103f, 0.3301f, 0.0308f }, + { -0.2256f, 0.3174f, 0.1333f }, + { -0.2051f, 0.1777f, 0.1333f }, + { -0.4204f, 0.2285f, 0.1128f }, + { 0.2256f, 0.1523f, 0.1538f }, + { 0.0308f, 0.1396f, 0.0615f }, + { 0.0718f, 0.0000f, 0.1641f }, + { -0.1128f, 0.0381f, 0.1128f }, + { 0.0718f, 0.1396f, -0.0103f }, + { -0.0718f, 0.1396f, -0.0205f }, + { -0.0718f, 0.0762f, 0.0615f }, + { -0.2563f, 0.0254f, 0.0000f }, + { 0.1553f, 0.1582f, 0.0601f }, + { -0.0132f, 0.0791f, 0.0415f }, + { -0.0259f, 0.0352f, 0.0786f }, + { -0.1943f, -0.0088f, 0.1436f }, + { 0.0127f, 0.1143f, 0.0044f }, + { -0.1426f, 0.1055f, -0.0234f }, + { -0.0776f, 0.0527f, 0.0044f }, + { -0.3882f, -0.0352f, 0.0044f }, + { 0.4141f, 0.0264f, 0.0137f }, + { 0.0903f, 0.0000f, 0.0044f }, + { 0.1294f, -0.1143f, 0.0508f }, + { -0.0259f, -0.0879f, 0.0229f }, + { 0.1294f, 0.0439f, -0.0605f }, + { 0.0127f, 0.0176f, -0.1440f }, + { 0.0127f, -0.0176f, -0.0420f }, + { -0.1426f, -0.0527f, -0.1348f }, + { 0.3652f, 0.4199f, 0.2012f }, + { 0.0752f, 0.2261f, 0.0620f }, + { 0.0645f, 0.1484f, 0.1318f }, + { -0.0859f, 0.1353f, 0.1318f }, + { 0.1074f, 0.2778f, -0.0908f }, + { -0.1611f, 0.3164f, -0.1465f }, + { 0.0000f, 0.1743f, 0.0063f }, + { -0.2363f, 0.2261f, -0.0073f }, + { 0.4297f, 0.3555f, -0.0073f }, + { 0.2686f, 0.1484f, 0.0063f }, + { 0.2148f, 0.0576f, 0.0762f }, + { 0.0000f, 0.0190f, 0.0342f }, + { 0.2578f, 0.2905f, -0.2300f }, + { 0.0752f, 0.1353f, -0.2163f }, + { 0.0752f, 0.0967f, -0.0630f }, + { -0.0645f, 0.0835f, -0.0493f }, + { 0.1206f, -0.0054f, 0.2803f }, + { -0.0005f, 0.0244f, 0.1187f }, + { 0.0117f, -0.1255f, 0.2520f }, + { -0.2422f, -0.0654f, 0.2710f }, + { 0.0479f, 0.0347f, 0.0615f }, + { -0.1694f, 0.0244f, 0.0327f }, + { -0.0972f, -0.0454f, 0.1470f }, + { -0.4473f, -0.1455f, 0.0708f }, + { 0.3018f, -0.1157f, 0.2329f }, + { 0.1084f, -0.1055f, 0.1567f }, + { 0.1206f, -0.2456f, 0.1851f }, + { -0.1572f, -0.2656f, 0.2041f }, + { 0.1328f, -0.0557f, 0.0234f }, + { -0.0122f, -0.0654f, -0.0146f }, + { -0.0122f, -0.1357f, 0.0708f }, + { -0.2300f, -0.2358f, 0.0518f }, + { 0.2588f, 0.2451f, 0.3184f }, + { 0.1294f, 0.1494f, 0.2231f }, + { 0.2588f, 0.1016f, 0.2900f }, + { -0.0581f, 0.0415f, 0.1567f }, + { 0.1724f, 0.2930f, 0.1377f }, + { -0.1157f, 0.2451f, 0.0234f }, + { -0.0005f, 0.1016f, 0.0996f }, + { -0.2163f, 0.0654f, 0.0996f }, + { 0.6768f, 0.0654f, 0.2422f }, + { 0.2158f, 0.0059f, 0.1470f }, + { 0.3022f, 0.0537f, 0.1758f }, + { 0.0571f, -0.0659f, 0.1089f }, + { 0.3164f, 0.0776f, 0.0518f }, + { 0.0430f, 0.0654f, 0.0234f }, + { 0.0859f, -0.0181f, 0.0615f }, + { -0.0581f, -0.0420f, 0.0327f }, + { 0.4556f, 0.0659f, 0.2202f }, + { 0.1211f, 0.0396f, 0.0562f }, + { 0.2124f, -0.1187f, 0.1279f }, + { -0.0308f, -0.0659f, 0.0869f }, + { 0.1514f, 0.1055f, -0.0054f }, + { -0.0205f, 0.0527f, -0.0259f }, + { 0.0400f, -0.0132f, 0.0356f }, + { -0.1016f, -0.0132f, -0.0054f }, + { 0.5264f, -0.2637f, 0.0562f }, + { 0.3340f, -0.1582f, 0.0459f }, + { 0.3135f, -0.3032f, 0.1074f }, + { 0.0605f, -0.1714f, 0.0972f }, + { 0.4253f, -0.0791f, -0.0771f }, + { 0.1211f, -0.0264f, -0.0977f }, + { 0.1919f, -0.1187f, 0.0049f }, + { 0.0200f, -0.1714f, -0.0977f }, + { 0.6699f, 0.3623f, 0.1587f }, + { 0.4766f, 0.2549f, 0.2202f }, + { 0.3276f, 0.2280f, 0.1382f }, + { 0.0596f, 0.0532f, 0.1074f }, + { 0.2231f, 0.2549f, 0.0049f }, + { 0.0298f, 0.1875f, -0.0669f }, + { 0.0894f, 0.0938f, 0.0459f }, + { -0.0298f, 0.0938f, 0.0049f }, + { 0.8936f, 0.1206f, -0.0156f }, + { 0.6255f, 0.1475f, 0.0767f }, + { 0.4912f, -0.0405f, 0.0869f }, + { 0.2979f, -0.0405f, 0.0767f }, + { 0.6553f, 0.2817f, -0.0874f }, + { 0.3276f, 0.1606f, -0.0977f }, + { 0.2085f, 0.0400f, -0.0259f }, + { 0.0444f, -0.0273f, -0.0054f }, +}; + +/*! \brief PRBA[4:7] Difference vector quantization table */ +const float ir77_ambe_prba_dif47_vq[64][4] = { + { 0.0044f, 0.0229f, 0.0151f, -0.0024f }, + { 0.0044f, -0.0298f, 0.0239f, 0.0142f }, + { -0.0308f, 0.0757f, -0.0815f, -0.0356f }, + { -0.0483f, -0.0298f, -0.0464f, -0.0107f }, + { 0.0747f, 0.0098f, 0.0151f, -0.0439f }, + { 0.1099f, -0.0825f, 0.0327f, -0.0605f }, + { 0.0747f, 0.0361f, -0.0640f, -0.0938f }, + { 0.0396f, -0.0562f, -0.0376f, -0.0605f }, + { -0.0659f, -0.0166f, 0.0327f, 0.0059f }, + { -0.0835f, -0.1089f, 0.0151f, 0.0225f }, + { -0.1362f, -0.0034f, -0.0903f, -0.0356f }, + { -0.1538f, -0.1221f, -0.0991f, -0.0356f }, + { -0.0132f, -0.0298f, 0.0151f, -0.0356f }, + { 0.0044f, -0.1089f, 0.0151f, -0.0273f }, + { -0.0308f, -0.0298f, -0.0991f, -0.0938f }, + { -0.0483f, -0.1221f, -0.0728f, -0.0522f }, + { -0.0127f, 0.0991f, 0.0933f, -0.0137f }, + { -0.0293f, 0.0142f, 0.0767f, 0.0000f }, + { -0.0791f, 0.1416f, -0.0063f, -0.0137f }, + { -0.0625f, 0.0425f, 0.0020f, 0.0000f }, + { 0.0703f, 0.0566f, 0.0850f, -0.0820f }, + { 0.0371f, -0.0142f, 0.0767f, -0.0615f }, + { 0.0039f, 0.1133f, 0.0103f, -0.0889f }, + { 0.0039f, 0.0142f, -0.0063f, -0.0615f }, + { -0.1289f, 0.0708f, 0.1016f, 0.0137f }, + { -0.1289f, -0.0425f, 0.1099f, 0.0000f }, + { -0.1787f, 0.0708f, 0.0186f, -0.0410f }, + { -0.1787f, -0.0425f, 0.0020f, 0.0068f }, + { -0.0625f, 0.0283f, 0.0684f, -0.0752f }, + { -0.0459f, -0.0708f, 0.1016f, -0.0615f }, + { -0.0791f, 0.0425f, -0.0146f, -0.0820f }, + { -0.0791f, -0.0566f, 0.0020f, -0.0684f }, + { 0.0981f, 0.0474f, -0.0029f, 0.0791f }, + { 0.0640f, -0.0288f, 0.0186f, 0.0688f }, + { 0.0640f, 0.0601f, -0.0996f, 0.0483f }, + { 0.0298f, -0.0288f, -0.0674f, 0.0688f }, + { 0.1836f, 0.0093f, -0.0029f, -0.0234f }, + { 0.1665f, -0.0796f, 0.0186f, 0.0483f }, + { 0.1494f, 0.0347f, -0.1104f, -0.0439f }, + { 0.1152f, -0.0542f, -0.0781f, 0.0278f }, + { -0.0044f, -0.0161f, 0.0078f, 0.0791f }, + { -0.0044f, -0.1050f, -0.0029f, 0.1099f }, + { -0.0386f, 0.0220f, -0.0996f, 0.0483f }, + { -0.0728f, -0.0923f, -0.1211f, 0.0483f }, + { 0.0640f, -0.0415f, 0.0078f, -0.0029f }, + { 0.0640f, -0.1304f, 0.0400f, 0.0278f }, + { 0.0298f, -0.0161f, -0.0996f, -0.0132f }, + { 0.0469f, -0.1304f, -0.0996f, 0.0073f }, + { 0.0684f, 0.1128f, 0.0811f, 0.0586f }, + { 0.0171f, 0.0151f, 0.0996f, 0.0732f }, + { 0.0000f, 0.1128f, -0.0396f, 0.0586f }, + { 0.0000f, 0.0273f, -0.0117f, 0.0513f }, + { 0.1538f, 0.1250f, 0.0625f, 0.0000f }, + { 0.1196f, 0.0029f, 0.0903f, 0.0146f }, + { 0.0684f, 0.1128f, -0.0303f, -0.0146f }, + { 0.0684f, 0.0151f, -0.0303f, 0.0073f }, + { -0.0513f, 0.0640f, 0.0439f, 0.0732f }, + { -0.0854f, -0.0337f, 0.0811f, 0.0952f }, + { -0.1025f, 0.0640f, -0.0303f, 0.0586f }, + { -0.0854f, -0.0215f, -0.0210f, 0.0659f }, + { 0.0342f, 0.0518f, 0.0439f, 0.0073f }, + { 0.0342f, -0.0581f, 0.0811f, 0.0220f }, + { 0.0000f, 0.0396f, -0.0396f, -0.0073f }, + { 0.0000f, -0.0337f, -0.0210f, 0.0146f }, +}; + +/*! \brief HOC 1st block Sum vector quantization table */ +const float ir77_ambe_hoc0_sum_vq[128][4] = { + { -0.1294f, 0.0190f, 0.0112f, -0.0073f }, + { -0.2329f, 0.0698f, 0.0562f, -0.0630f }, + { -0.1812f, 0.0952f, 0.0562f, 0.1597f }, + { -0.3105f, 0.2476f, 0.1909f, 0.0762f }, + { -0.0259f, 0.0190f, -0.0337f, -0.0073f }, + { -0.1294f, 0.1206f, -0.0337f, -0.0630f }, + { -0.0518f, 0.0698f, -0.1011f, 0.0205f }, + { -0.1035f, 0.2983f, 0.0337f, 0.1040f }, + { -0.0518f, 0.0698f, 0.0337f, -0.1187f }, + { -0.1553f, 0.1460f, 0.1011f, -0.1743f }, + { -0.1035f, 0.1460f, 0.1011f, -0.0073f }, + { -0.1035f, 0.3491f, 0.2358f, -0.0352f }, + { 0.0776f, -0.0317f, -0.1011f, -0.1187f }, + { 0.0518f, 0.1206f, -0.0562f, -0.2578f }, + { 0.0000f, 0.1460f, -0.0562f, -0.0630f }, + { 0.0518f, 0.2983f, 0.0112f, -0.1187f }, + { -0.1416f, 0.0151f, -0.0747f, 0.0493f }, + { -0.2905f, 0.1665f, 0.0000f, -0.0356f }, + { -0.2012f, 0.1060f, -0.1245f, 0.1060f }, + { -0.3799f, 0.2573f, -0.0747f, 0.1060f }, + { -0.1118f, -0.0757f, -0.2241f, 0.0210f }, + { -0.2310f, 0.0454f, -0.1245f, -0.0640f }, + { -0.0225f, 0.0454f, -0.1992f, 0.1626f }, + { -0.2012f, 0.1968f, -0.2490f, 0.0493f }, + { -0.0820f, -0.0151f, -0.0996f, -0.0923f }, + { -0.1714f, 0.1968f, -0.0996f, -0.1772f }, + { -0.1118f, 0.2271f, -0.0996f, -0.0356f }, + { -0.2607f, 0.3784f, 0.0000f, -0.1206f }, + { 0.0669f, -0.0757f, -0.3735f, -0.0640f }, + { -0.1416f, -0.0151f, -0.2739f, -0.2622f }, + { 0.0073f, 0.1060f, -0.1992f, -0.0356f }, + { 0.0073f, 0.3179f, -0.1992f, -0.0356f }, + { 0.1543f, -0.0957f, 0.1250f, 0.0732f }, + { 0.0771f, 0.0479f, 0.1250f, 0.0000f }, + { 0.1929f, 0.0479f, 0.2549f, 0.1709f }, + { 0.0000f, 0.1914f, 0.2363f, 0.1221f }, + { 0.2700f, -0.2871f, 0.0137f, 0.1221f }, + { 0.1929f, 0.0000f, -0.0234f, 0.0244f }, + { 0.4629f, 0.1436f, 0.0508f, 0.1465f }, + { 0.1543f, 0.2393f, 0.0508f, 0.2441f }, + { 0.3086f, 0.0957f, 0.1807f, -0.0244f }, + { 0.1157f, 0.1436f, 0.1992f, -0.1221f }, + { 0.3472f, 0.2393f, 0.1992f, 0.1221f }, + { 0.1929f, 0.3350f, 0.2178f, 0.0244f }, + { 0.3857f, -0.0957f, 0.0322f, 0.0488f }, + { 0.3086f, 0.2393f, 0.0322f, -0.1221f }, + { 0.5786f, 0.2871f, 0.1621f, 0.0488f }, + { 0.2314f, 0.4307f, -0.0049f, 0.0732f }, + { 0.1245f, -0.1230f, -0.0464f, 0.0410f }, + { 0.0532f, -0.0137f, -0.0669f, 0.0410f }, + { 0.1958f, 0.0137f, -0.0259f, 0.2051f }, + { 0.0176f, 0.0957f, 0.0356f, 0.1348f }, + { 0.2671f, -0.1504f, -0.1284f, 0.0176f }, + { 0.1245f, -0.0137f, -0.1489f, 0.0410f }, + { 0.3027f, 0.0137f, -0.2104f, 0.1113f }, + { 0.0889f, 0.1504f, -0.1694f, 0.0879f }, + { 0.1958f, -0.0410f, 0.0151f, -0.1230f }, + { 0.1245f, 0.0957f, -0.0464f, -0.0762f }, + { 0.3027f, 0.1230f, -0.0259f, 0.0176f }, + { 0.1245f, 0.2051f, 0.0767f, 0.0176f }, + { 0.4810f, -0.1777f, -0.1899f, -0.0293f }, + { 0.3027f, -0.0137f, -0.1694f, -0.1465f }, + { 0.5522f, 0.1230f, -0.0669f, -0.0762f }, + { 0.2671f, 0.2324f, -0.2310f, -0.0059f }, + { -0.5029f, -0.1719f, 0.1777f, -0.0068f }, + { -0.7456f, -0.0996f, 0.0986f, 0.0195f }, + { -0.4336f, 0.0088f, 0.2041f, 0.1514f }, + { -0.6763f, 0.2256f, 0.2305f, -0.0068f }, + { -0.3643f, -0.3164f, -0.0068f, -0.0859f }, + { -0.5723f, -0.1357f, -0.0596f, -0.0859f }, + { -0.3643f, 0.0088f, -0.0332f, 0.1250f }, + { -0.5029f, 0.0811f, 0.0459f, 0.0195f }, + { -0.3643f, -0.0996f, 0.0723f, -0.1650f }, + { -0.5723f, 0.0449f, 0.0459f, -0.1914f }, + { -0.3643f, 0.0088f, 0.1250f, -0.0332f }, + { -0.3989f, 0.1533f, 0.1514f, -0.1650f }, + { -0.2603f, -0.2080f, -0.1650f, -0.1650f }, + { -0.2603f, -0.0273f, -0.0859f, -0.2441f }, + { -0.2256f, -0.1357f, -0.1387f, -0.0068f }, + { -0.3643f, 0.0811f, -0.0332f, -0.1650f }, + { -0.6401f, -0.4102f, -0.0518f, 0.0444f }, + { -0.9185f, -0.2461f, -0.1035f, -0.1079f }, + { -0.4731f, -0.1914f, 0.0000f, 0.1460f }, + { -0.6958f, 0.0273f, -0.1294f, 0.0190f }, + { -0.3618f, -0.5195f, -0.2847f, -0.1333f }, + { -0.6401f, -0.3008f, -0.3364f, -0.0825f }, + { -0.4175f, -0.2461f, -0.1812f, 0.0190f }, + { -0.4175f, -0.0273f, -0.2070f, 0.0444f }, + { -0.5288f, -0.3008f, -0.1035f, -0.2349f }, + { -0.7515f, -0.0273f, -0.1812f, -0.2095f }, + { -0.3618f, -0.0820f, -0.0518f, -0.0571f }, + { -0.5288f, 0.3008f, -0.0776f, -0.0825f }, + { -0.0835f, -0.4102f, -0.3882f, -0.2349f }, + { -0.4175f, -0.1914f, -0.2847f, -0.2095f }, + { -0.2505f, -0.1367f, -0.3623f, -0.0825f }, + { -0.4175f, 0.0820f, -0.2329f, -0.1333f }, + { -0.1489f, -0.2637f, 0.1646f, 0.0000f }, + { -0.2681f, -0.1230f, 0.2231f, -0.0864f }, + { -0.1489f, -0.0527f, 0.2378f, 0.2305f }, + { -0.2085f, 0.0645f, 0.2378f, 0.0576f }, + { 0.0298f, -0.2871f, 0.0620f, 0.0576f }, + { -0.0298f, -0.1465f, 0.0913f, -0.0576f }, + { 0.0298f, -0.0996f, 0.0474f, 0.1729f }, + { -0.0894f, -0.0293f, 0.0474f, 0.0864f }, + { 0.0596f, -0.2637f, 0.2085f, -0.1152f }, + { -0.1191f, -0.0527f, 0.1792f, -0.2017f }, + { -0.0298f, -0.0762f, 0.1938f, 0.0288f }, + { -0.1489f, -0.0059f, 0.0913f, -0.0864f }, + { 0.1787f, -0.1934f, 0.0474f, -0.0864f }, + { 0.0000f, -0.0996f, 0.0327f, -0.2017f }, + { 0.0596f, -0.0762f, 0.0181f, 0.0000f }, + { -0.0298f, -0.0293f, 0.0474f, -0.0576f }, + { -0.2231f, -0.4468f, 0.0298f, 0.1191f }, + { -0.2847f, -0.1587f, 0.0898f, 0.0894f }, + { -0.2539f, -0.1299f, -0.0103f, 0.2383f }, + { -0.2231f, -0.0146f, 0.0098f, 0.0596f }, + { 0.1460f, -0.4468f, -0.1904f, 0.0298f }, + { -0.1924f, -0.3027f, -0.1704f, 0.0298f }, + { 0.0229f, -0.1875f, -0.1304f, 0.2085f }, + { -0.1001f, -0.1011f, -0.0503f, 0.1191f }, + { -0.0693f, -0.3315f, -0.0503f, -0.1191f }, + { -0.1924f, -0.1587f, 0.0098f, -0.0894f }, + { -0.1001f, -0.1875f, 0.0498f, 0.0894f }, + { -0.1924f, -0.0723f, 0.1099f, 0.0000f }, + { 0.1768f, -0.2451f, -0.1904f, -0.2085f }, + { -0.0693f, -0.1875f, -0.1904f, -0.2085f }, + { -0.0078f, -0.1587f, -0.1304f, -0.0298f }, + { -0.0693f, -0.0723f, -0.0103f, 0.0000f }, +}; + +/*! \brief HOC 1st block Difference vector quantization table */ +const float ir77_ambe_hoc0_dif_vq[8][4] = { + { -0.0303f, -0.1313f, 0.0117f, 0.0107f }, + { -0.2422f, -0.0771f, -0.0508f, -0.0166f }, + { 0.1211f, -0.0771f, -0.0352f, 0.0107f }, + { 0.0000f, 0.0132f, -0.0742f, 0.0264f }, + { 0.0000f, -0.0049f, 0.0352f, -0.0166f }, + { -0.1211f, 0.0493f, 0.0430f, -0.0049f }, + { 0.2119f, 0.0854f, 0.0195f, 0.0146f }, + { 0.0303f, 0.1396f, 0.0039f, -0.0283f }, +}; + +/*! \brief HOC 2nd block Sum vector quantization table */ +const float ir77_ambe_hoc1_sum_vq[128][4] = { + { 0.4424f, -0.0303f, 0.0767f, 0.1050f }, + { 0.2607f, 0.1816f, 0.1997f, 0.0649f }, + { 0.1699f, 0.0000f, 0.0767f, -0.0151f }, + { 0.0791f, 0.1211f, 0.1997f, -0.0552f }, + { 0.2153f, -0.0605f, -0.1079f, 0.0249f }, + { 0.0791f, 0.1816f, -0.0259f, -0.0752f }, + { -0.0117f, -0.0303f, -0.0054f, -0.0151f }, + { -0.1025f, 0.1514f, 0.0972f, -0.1152f }, + { 0.1245f, 0.1211f, 0.0767f, 0.1851f }, + { 0.0791f, 0.2725f, 0.1587f, 0.1050f }, + { -0.0117f, 0.1211f, 0.0767f, 0.0249f }, + { -0.1025f, 0.3027f, 0.1997f, -0.0752f }, + { 0.0337f, 0.0605f, -0.0464f, 0.0850f }, + { -0.0117f, 0.3936f, -0.0259f, 0.0449f }, + { -0.1479f, 0.0908f, -0.0669f, -0.0552f }, + { -0.2388f, 0.3027f, -0.0054f, -0.0952f }, + { 0.3013f, -0.2007f, 0.1489f, 0.0947f }, + { 0.1621f, -0.0195f, 0.2212f, 0.0547f }, + { 0.1157f, -0.2266f, 0.2031f, -0.0854f }, + { -0.0234f, -0.0195f, 0.2754f, -0.0854f }, + { 0.1621f, -0.2007f, 0.0405f, 0.0146f }, + { 0.0229f, -0.0195f, 0.1309f, -0.0054f }, + { -0.1162f, -0.2266f, 0.1128f, -0.1255f }, + { -0.2090f, -0.0195f, 0.1670f, -0.1255f }, + { 0.1157f, -0.0713f, 0.1489f, 0.1748f }, + { -0.0234f, 0.0840f, 0.2031f, 0.1147f }, + { -0.1162f, -0.0972f, 0.1489f, 0.0347f }, + { -0.2090f, 0.0840f, 0.2031f, -0.0054f }, + { -0.0698f, -0.0713f, 0.0044f, 0.0547f }, + { -0.1626f, 0.1099f, 0.0405f, 0.0146f }, + { -0.3018f, -0.1230f, 0.0225f, -0.0054f }, + { -0.3945f, 0.1616f, 0.1309f, -0.1255f }, + { 0.1816f, -0.0063f, 0.0088f, 0.1206f }, + { 0.0908f, 0.0654f, 0.1143f, 0.0576f }, + { 0.0000f, -0.1260f, 0.0439f, 0.0366f }, + { -0.0908f, 0.0176f, 0.0967f, -0.0054f }, + { 0.0000f, -0.1021f, -0.0615f, 0.0996f }, + { -0.0454f, 0.0415f, -0.0088f, 0.0366f }, + { -0.1362f, -0.1260f, -0.0439f, -0.0474f }, + { -0.3179f, 0.0894f, -0.0264f, -0.0474f }, + { 0.0000f, 0.0415f, -0.0615f, 0.2676f }, + { -0.0908f, 0.1851f, 0.0264f, 0.1626f }, + { -0.1362f, 0.0176f, 0.0264f, 0.0996f }, + { -0.2725f, 0.2329f, 0.1143f, 0.0786f }, + { -0.1362f, 0.0415f, -0.1143f, 0.1416f }, + { -0.2725f, 0.1851f, -0.0967f, 0.0996f }, + { -0.3179f, -0.0303f, -0.1494f, 0.0786f }, + { -0.4995f, 0.2329f, -0.0439f, 0.0156f }, + { 0.0820f, -0.2373f, 0.0322f, 0.1699f }, + { -0.0117f, -0.1582f, 0.1826f, 0.0820f }, + { -0.0586f, -0.3428f, 0.1182f, 0.0820f }, + { -0.1992f, -0.1846f, 0.2686f, -0.0498f }, + { -0.1055f, -0.2637f, -0.0537f, 0.1699f }, + { -0.1523f, -0.1582f, 0.0322f, 0.0381f }, + { -0.2930f, -0.3691f, -0.0322f, -0.0059f }, + { -0.3867f, -0.1582f, 0.1182f, -0.0718f }, + { -0.1055f, -0.1318f, 0.0752f, 0.2578f }, + { -0.1992f, 0.0264f, 0.1396f, 0.1699f }, + { -0.2930f, -0.2637f, 0.1396f, 0.1040f }, + { -0.3398f, 0.0000f, 0.2256f, 0.1040f }, + { -0.2461f, -0.1318f, -0.0322f, 0.1479f }, + { -0.3398f, 0.0000f, 0.0537f, 0.0601f }, + { -0.4805f, -0.2109f, -0.0322f, 0.0820f }, + { -0.6211f, -0.0527f, 0.0967f, -0.0059f }, + { 0.7163f, 0.0000f, -0.0718f, 0.0054f }, + { 0.4648f, 0.1777f, 0.0161f, -0.0161f }, + { 0.2134f, -0.0508f, -0.0278f, -0.0806f }, + { 0.2637f, 0.1523f, 0.0820f, -0.1235f }, + { 0.4146f, -0.0254f, -0.1816f, -0.0806f }, + { 0.2637f, 0.1270f, -0.1377f, -0.1450f }, + { 0.1631f, -0.0508f, -0.1816f, -0.1880f }, + { 0.0122f, 0.1523f, -0.0498f, -0.2310f }, + { 0.3643f, 0.1270f, -0.1157f, 0.0913f }, + { 0.3140f, 0.3301f, 0.0381f, 0.0269f }, + { 0.1631f, 0.0762f, -0.0718f, -0.0161f }, + { 0.1128f, 0.2793f, 0.0601f, -0.0806f }, + { 0.2134f, 0.1270f, -0.2476f, 0.0269f }, + { 0.1631f, 0.3047f, -0.1597f, -0.0806f }, + { 0.0625f, 0.1016f, -0.2256f, -0.1021f }, + { -0.0381f, 0.2539f, -0.1157f, -0.0806f }, + { 0.5156f, -0.2051f, 0.0176f, -0.0054f }, + { 0.3281f, -0.0371f, 0.1230f, -0.0698f }, + { 0.2813f, -0.2051f, 0.0352f, -0.1558f }, + { 0.1406f, -0.0161f, 0.1582f, -0.1558f }, + { 0.2344f, -0.2051f, -0.1055f, -0.0698f }, + { 0.0938f, 0.0049f, -0.0176f, -0.1343f }, + { 0.0938f, -0.1841f, -0.0703f, -0.1558f }, + { -0.0469f, -0.0791f, 0.0703f, -0.2632f }, + { 0.2813f, -0.1001f, 0.0176f, 0.0591f }, + { 0.1406f, 0.1099f, 0.0352f, 0.0161f }, + { 0.0938f, -0.1001f, 0.0352f, -0.0698f }, + { 0.0000f, 0.0259f, 0.0527f, -0.1128f }, + { 0.0938f, -0.0371f, -0.0527f, 0.0161f }, + { 0.0000f, 0.0889f, -0.0352f, -0.0483f }, + { -0.0938f, -0.0581f, -0.0527f, -0.1128f }, + { -0.1875f, 0.0889f, 0.0176f, -0.1772f }, + { 0.3848f, -0.0942f, -0.1001f, 0.1318f }, + { 0.3037f, 0.0938f, 0.0259f, 0.0220f }, + { 0.1011f, -0.1479f, -0.1001f, 0.0000f }, + { 0.0605f, 0.0132f, 0.0259f, 0.0000f }, + { 0.2227f, -0.1479f, -0.2891f, 0.0000f }, + { 0.0605f, -0.0137f, -0.1211f, -0.0659f }, + { 0.0200f, -0.1211f, -0.2051f, -0.0659f }, + { -0.1016f, -0.0137f, -0.1631f, -0.1978f }, + { 0.1416f, 0.0132f, -0.1421f, 0.1099f }, + { 0.1416f, 0.2012f, -0.0791f, 0.0879f }, + { -0.0205f, -0.0137f, -0.1001f, 0.0220f }, + { -0.0610f, 0.2012f, -0.0161f, 0.0220f }, + { 0.0200f, -0.0405f, -0.2681f, 0.0659f }, + { -0.0205f, 0.1475f, -0.1841f, 0.0879f }, + { -0.1421f, 0.0400f, -0.2051f, -0.0220f }, + { -0.2231f, 0.2549f, -0.2051f, -0.0220f }, + { 0.3267f, -0.3203f, -0.0557f, 0.0479f }, + { 0.1255f, -0.0957f, 0.0557f, 0.0479f }, + { 0.0752f, -0.3428f, 0.0186f, -0.0718f }, + { -0.0254f, -0.1182f, 0.0742f, -0.0957f }, + { 0.0752f, -0.3428f, -0.1484f, 0.0479f }, + { -0.0254f, -0.1406f, -0.0742f, -0.0239f }, + { -0.0757f, -0.2979f, -0.2041f, -0.0718f }, + { -0.2266f, -0.1631f, -0.0186f, -0.1675f }, + { 0.1758f, -0.1855f, -0.0928f, 0.1914f }, + { -0.0254f, -0.0059f, 0.0557f, 0.1196f }, + { -0.0757f, -0.2529f, -0.0371f, -0.0239f }, + { -0.1763f, -0.0059f, 0.0186f, -0.0479f }, + { -0.0757f, -0.1631f, -0.1484f, 0.0718f }, + { -0.1763f, -0.0283f, -0.0742f, 0.0239f }, + { -0.2769f, -0.1855f, -0.1484f, -0.0479f }, + { -0.4277f, -0.0508f, -0.0928f, -0.0957f }, +}; + +/*! \brief HOC 2nd block Difference vector quantization table */ +const float ir77_ambe_hoc1_dif_vq[8][4] = { + { -0.0122f, 0.1094f, 0.0498f, -0.0337f }, + { 0.1313f, 0.0957f, -0.0415f, -0.0122f }, + { 0.0356f, -0.0137f, 0.0581f, 0.0200f }, + { 0.1792f, -0.0684f, 0.0000f, 0.0093f }, + { -0.1797f, 0.0547f, 0.0083f, -0.0068f }, + { -0.0361f, 0.0273f, -0.0664f, 0.0308f }, + { -0.1079f, -0.0957f, 0.0332f, 0.0146f }, + { 0.0117f, -0.0820f, -0.0581f, -0.0444f }, +}; + +/*! \brief HOC 3rd block Sum vector quantization table */ +const float ir77_ambe_hoc2_sum_vq[128][4] = { + { -0.0093f, 0.1221f, 0.0742f, -0.0044f }, + { 0.1021f, 0.3101f, 0.1025f, -0.0044f }, + { 0.1021f, -0.0283f, 0.0317f, -0.0210f }, + { 0.1763f, 0.0845f, 0.0601f, 0.0039f }, + { 0.1392f, 0.0093f, 0.1733f, -0.0542f }, + { 0.2505f, 0.1973f, 0.1592f, -0.0210f }, + { 0.2876f, -0.1787f, 0.1450f, -0.0542f }, + { 0.3989f, 0.0093f, 0.1309f, -0.0376f }, + { -0.1577f, 0.1221f, -0.0107f, 0.0288f }, + { -0.0835f, 0.3853f, -0.0107f, 0.0039f }, + { -0.0464f, -0.0659f, -0.0391f, 0.0371f }, + { 0.0278f, 0.1221f, -0.0391f, 0.0620f }, + { -0.0093f, -0.0283f, 0.0601f, 0.0288f }, + { 0.1021f, 0.1597f, 0.0317f, 0.0039f }, + { 0.1021f, -0.1787f, -0.0107f, -0.0127f }, + { 0.1763f, -0.0283f, 0.0034f, 0.0205f }, + { 0.1479f, 0.0952f, -0.0601f, -0.0195f }, + { 0.2271f, 0.3379f, -0.0771f, 0.0195f }, + { 0.2271f, -0.0435f, -0.0771f, -0.0039f }, + { 0.3457f, 0.1299f, -0.0942f, -0.0273f }, + { 0.2666f, 0.0259f, 0.0083f, 0.0039f }, + { 0.4248f, 0.2686f, 0.0596f, 0.0273f }, + { 0.4644f, -0.1821f, -0.0088f, -0.0039f }, + { 0.5830f, 0.0605f, -0.0430f, -0.0195f }, + { -0.0103f, 0.0952f, -0.1455f, 0.0430f }, + { 0.0688f, 0.2339f, -0.1284f, 0.0508f }, + { 0.0688f, -0.0781f, -0.1968f, 0.0742f }, + { 0.1875f, 0.0605f, -0.1968f, 0.0898f }, + { 0.1084f, -0.0088f, -0.0942f, 0.0586f }, + { 0.2271f, 0.1646f, -0.0601f, 0.0742f }, + { 0.2271f, -0.1821f, -0.1797f, 0.0352f }, + { 0.3853f, -0.0088f, -0.1626f, 0.0820f }, + { -0.1245f, 0.0571f, 0.0742f, -0.1616f }, + { -0.0581f, 0.2534f, 0.0742f, -0.1206f }, + { -0.0581f, -0.0737f, -0.0107f, -0.1821f }, + { 0.0083f, 0.0571f, 0.0034f, -0.1001f }, + { 0.0083f, -0.0410f, 0.1167f, -0.1309f }, + { 0.0747f, 0.1226f, 0.1025f, -0.1411f }, + { 0.1079f, -0.1719f, 0.0742f, -0.1616f }, + { 0.2075f, -0.0083f, 0.0459f, -0.1309f }, + { -0.2905f, 0.0571f, 0.0176f, -0.1001f }, + { -0.2241f, 0.2207f, -0.0391f, -0.0796f }, + { -0.2241f, -0.1064f, -0.0957f, -0.1104f }, + { -0.0913f, 0.0898f, -0.0815f, -0.0386f }, + { -0.1245f, -0.0410f, 0.0459f, -0.0591f }, + { -0.0581f, 0.1226f, 0.0034f, -0.0693f }, + { -0.0581f, -0.2373f, -0.0532f, -0.1104f }, + { 0.0083f, -0.0410f, -0.0107f, -0.0283f }, + { -0.0435f, 0.0869f, -0.0903f, -0.1709f }, + { 0.0259f, 0.2456f, -0.0723f, -0.1343f }, + { 0.0952f, -0.0718f, -0.1084f, -0.1709f }, + { 0.1646f, 0.0869f, -0.1445f, -0.1221f }, + { 0.1299f, -0.0083f, -0.0361f, -0.0732f }, + { 0.2339f, 0.1504f, 0.0181f, -0.1099f }, + { 0.2339f, -0.1987f, -0.0542f, -0.1343f }, + { 0.3379f, -0.0083f, -0.1265f, -0.1343f }, + { -0.1821f, 0.0552f, -0.1626f, -0.0732f }, + { -0.1128f, 0.2139f, -0.2168f, 0.0000f }, + { -0.0781f, -0.1035f, -0.2168f, -0.0854f }, + { 0.0259f, 0.0552f, -0.2529f, -0.0610f }, + { -0.0088f, -0.0083f, -0.1084f, -0.0366f }, + { 0.0605f, 0.0869f, -0.1084f, -0.0244f }, + { 0.0952f, -0.2305f, -0.1987f, -0.0854f }, + { 0.1299f, -0.0718f, -0.1445f, -0.0366f }, + { -0.1445f, 0.0757f, 0.1685f, 0.0718f }, + { -0.0361f, 0.2441f, 0.1538f, 0.0718f }, + { -0.0361f, -0.1265f, 0.0806f, 0.0308f }, + { 0.0361f, 0.0757f, 0.0952f, 0.0615f }, + { 0.0000f, -0.0254f, 0.1978f, 0.0410f }, + { 0.1084f, 0.1431f, 0.2271f, 0.0718f }, + { 0.1084f, -0.1938f, 0.1392f, 0.0103f }, + { 0.2168f, -0.0254f, 0.1538f, 0.0718f }, + { -0.3252f, 0.0083f, 0.1099f, 0.1230f }, + { -0.2168f, 0.2104f, 0.0513f, 0.1128f }, + { -0.2529f, -0.1938f, 0.0073f, 0.1538f }, + { -0.1084f, 0.0083f, 0.0220f, 0.1128f }, + { -0.1084f, -0.0928f, 0.1245f, 0.1333f }, + { -0.0361f, 0.0757f, 0.0952f, 0.1641f }, + { -0.0361f, -0.2612f, 0.0513f, 0.1128f }, + { 0.0723f, -0.1265f, 0.0806f, 0.1436f }, + { 0.0171f, 0.0078f, -0.0039f, 0.0767f }, + { 0.0864f, 0.2300f, 0.0107f, 0.1484f }, + { 0.0864f, -0.0874f, -0.0186f, 0.0459f }, + { 0.1558f, 0.0713f, -0.0332f, 0.0767f }, + { 0.1211f, -0.0239f, 0.0547f, 0.0869f }, + { 0.2251f, 0.1348f, 0.0986f, 0.1382f }, + { 0.2251f, -0.2144f, -0.0039f, 0.0664f }, + { 0.3638f, -0.0239f, 0.0400f, 0.1177f }, + { -0.1563f, 0.0396f, -0.0918f, 0.1587f }, + { -0.0869f, 0.1665f, -0.1064f, 0.1382f }, + { -0.0869f, -0.1509f, -0.1211f, 0.1279f }, + { 0.0171f, 0.0396f, -0.1211f, 0.1587f }, + { 0.0171f, -0.0874f, -0.0186f, 0.1484f }, + { 0.0864f, 0.0713f, -0.0039f, 0.1997f }, + { 0.0864f, -0.2461f, -0.1064f, 0.1484f }, + { 0.1904f, -0.0557f, -0.0625f, 0.1792f }, + { -0.3115f, 0.0615f, 0.1914f, -0.0586f }, + { -0.2256f, 0.2256f, 0.1445f, -0.0352f }, + { -0.2256f, -0.1436f, 0.0508f, -0.0820f }, + { -0.0537f, 0.0205f, 0.0508f, -0.0273f }, + { -0.1396f, -0.1025f, 0.2070f, -0.0664f }, + { -0.0537f, 0.0615f, 0.1758f, -0.0586f }, + { -0.0537f, -0.2256f, 0.1602f, -0.0508f }, + { 0.0752f, -0.0615f, 0.0977f, -0.0273f }, + { -0.5693f, -0.0205f, 0.1133f, 0.0273f }, + { -0.4404f, 0.1846f, 0.0195f, -0.0117f }, + { -0.4404f, -0.2666f, -0.0273f, 0.0117f }, + { -0.2686f, -0.0205f, -0.0117f, 0.0352f }, + { -0.3115f, -0.1436f, 0.1445f, 0.0352f }, + { -0.1826f, 0.0205f, 0.0820f, -0.0039f }, + { -0.2256f, -0.3896f, 0.0352f, 0.0117f }, + { -0.1396f, -0.1436f, 0.0352f, 0.0195f }, + { -0.1353f, 0.0176f, -0.0405f, -0.0552f }, + { -0.0522f, 0.1958f, -0.0244f, 0.0063f }, + { -0.0522f, -0.1250f, -0.0728f, -0.0464f }, + { 0.0308f, 0.0176f, -0.0405f, -0.0024f }, + { 0.0308f, -0.1250f, 0.0239f, -0.0640f }, + { 0.0723f, 0.0532f, 0.0562f, -0.0288f }, + { 0.1138f, -0.3389f, -0.0083f, -0.0376f }, + { 0.2383f, -0.0894f, 0.0400f, -0.0112f }, + { -0.3843f, -0.0181f, -0.1050f, 0.0063f }, + { -0.3013f, 0.1958f, -0.1372f, 0.0679f }, + { -0.2598f, -0.2319f, -0.1855f, -0.0200f }, + { -0.1353f, -0.0181f, -0.1694f, 0.0415f }, + { -0.1768f, -0.1250f, -0.0566f, 0.0327f }, + { -0.0522f, 0.0532f, -0.0244f, 0.0503f }, + { -0.0522f, -0.3389f, -0.1372f, 0.0239f }, + { 0.0308f, -0.1250f, -0.0728f, 0.0327f }, +}; + +/*! \brief HOC 3rd block Difference vector quantization table */ +const float ir77_ambe_hoc2_dif_vq[8][4] = { + { 0.0112f, 0.0884f, 0.0020f, 0.0527f }, + { -0.1265f, 0.0884f, 0.0283f, -0.0020f }, + { 0.1719f, 0.0762f, -0.0156f, -0.0156f }, + { 0.0112f, 0.0029f, 0.0547f, -0.0430f }, + { -0.0117f, -0.0093f, -0.0771f, -0.0156f }, + { -0.1724f, -0.0581f, -0.0068f, -0.0156f }, + { 0.1260f, -0.0947f, -0.0156f, 0.0049f }, + { -0.0347f, -0.0947f, 0.0459f, 0.0391f }, +}; + +/*! \brief HOC 4th block Sum vector quantization table */ +const float ir77_ambe_hoc3_sum_vq[128][4] = { + { -0.0532f, 0.0049f, -0.1143f, -0.0688f }, + { 0.0317f, 0.1650f, -0.1396f, -0.1147f }, + { 0.0742f, -0.0151f, -0.1016f, 0.0688f }, + { 0.2441f, 0.1450f, -0.1904f, -0.0688f }, + { -0.2231f, 0.0649f, -0.2412f, 0.0918f }, + { -0.0957f, 0.2051f, -0.2412f, -0.0229f }, + { -0.0107f, 0.0049f, -0.1904f, 0.1836f }, + { 0.0317f, 0.1851f, -0.2285f, 0.0918f }, + { -0.2231f, -0.0552f, -0.0762f, -0.1606f }, + { -0.1382f, 0.0850f, -0.0889f, -0.1377f }, + { -0.0532f, -0.0952f, -0.0508f, 0.0229f }, + { 0.0317f, 0.0850f, -0.0762f, -0.0229f }, + { -0.3931f, -0.0552f, -0.1777f, 0.0229f }, + { -0.3081f, 0.1050f, -0.1523f, -0.0688f }, + { -0.2231f, -0.0952f, -0.1523f, 0.1377f }, + { -0.0957f, 0.1050f, -0.1523f, 0.0229f }, + { 0.0698f, -0.1812f, -0.1880f, -0.0859f }, + { 0.1499f, -0.0259f, -0.1470f, -0.1289f }, + { 0.2300f, -0.2588f, -0.1196f, 0.0645f }, + { 0.3501f, -0.0518f, -0.1743f, -0.0215f }, + { -0.0903f, -0.1553f, -0.2427f, -0.0215f }, + { -0.0103f, 0.0259f, -0.2427f, -0.0430f }, + { 0.0698f, -0.1553f, -0.1743f, 0.1289f }, + { 0.1499f, -0.0259f, -0.2427f, 0.0430f }, + { -0.0903f, -0.2329f, -0.0513f, -0.1289f }, + { -0.0503f, -0.0518f, -0.0923f, -0.1934f }, + { -0.0103f, -0.3623f, -0.0513f, 0.0000f }, + { 0.0698f, -0.1553f, -0.0376f, -0.0645f }, + { -0.2505f, -0.2329f, -0.1606f, -0.0430f }, + { -0.1704f, 0.0000f, -0.1606f, -0.0430f }, + { -0.0903f, -0.2070f, -0.0923f, 0.0859f }, + { -0.0503f, -0.0518f, -0.1333f, 0.0430f }, + { 0.1011f, 0.0479f, -0.0063f, -0.0718f }, + { 0.1416f, 0.2632f, -0.0190f, -0.1333f }, + { 0.2227f, 0.0239f, 0.0063f, 0.0513f }, + { 0.3848f, 0.2632f, 0.0317f, 0.0103f }, + { -0.0610f, 0.1196f, -0.0571f, 0.0513f }, + { 0.0200f, 0.3589f, -0.1206f, -0.0103f }, + { 0.1011f, 0.0957f, -0.0825f, 0.1743f }, + { 0.1821f, 0.2632f, -0.0825f, 0.0923f }, + { -0.1016f, 0.0000f, 0.0698f, -0.0923f }, + { -0.0205f, 0.1675f, 0.0317f, -0.1333f }, + { 0.0605f, 0.0000f, 0.0571f, 0.0103f }, + { 0.1821f, 0.1436f, 0.0190f, -0.0103f }, + { -0.2231f, 0.0479f, -0.0063f, -0.0103f }, + { -0.1826f, 0.2393f, -0.0444f, -0.0923f }, + { -0.1016f, 0.0718f, 0.0063f, 0.1128f }, + { 0.0200f, 0.1914f, -0.0698f, 0.0308f }, + { 0.1885f, -0.1538f, -0.0352f, -0.1313f }, + { 0.3218f, 0.0718f, -0.0195f, -0.1313f }, + { 0.3662f, -0.1743f, 0.0742f, -0.0054f }, + { 0.5439f, 0.0103f, -0.0039f, -0.0054f }, + { 0.0552f, -0.0513f, -0.0508f, -0.0054f }, + { 0.0996f, 0.0923f, -0.1133f, -0.0054f }, + { 0.2329f, -0.0923f, -0.0664f, 0.1206f }, + { 0.2773f, 0.0923f, -0.1133f, 0.0996f }, + { 0.0107f, -0.1743f, 0.1211f, -0.1313f }, + { 0.0996f, -0.0103f, 0.0430f, -0.1943f }, + { 0.1440f, -0.2153f, 0.1211f, -0.0474f }, + { 0.2329f, -0.0513f, 0.0586f, -0.0474f }, + { -0.1226f, -0.1128f, 0.0273f, 0.0156f }, + { -0.0781f, 0.0513f, -0.0195f, -0.0474f }, + { 0.0107f, -0.0718f, 0.0273f, 0.0786f }, + { 0.0552f, 0.0513f, -0.0039f, 0.0576f }, + { -0.1504f, 0.0000f, -0.0293f, -0.0054f }, + { -0.0645f, 0.2021f, -0.0293f, -0.0264f }, + { -0.0215f, 0.0000f, -0.0146f, 0.0366f }, + { 0.0645f, 0.1348f, 0.0146f, 0.0366f }, + { -0.3223f, 0.0898f, -0.1172f, 0.1206f }, + { -0.2363f, 0.2920f, -0.1611f, 0.0576f }, + { -0.1504f, 0.0449f, -0.0439f, 0.2256f }, + { -0.1074f, 0.2021f, -0.1025f, 0.1416f }, + { -0.3652f, -0.0449f, 0.0146f, -0.0684f }, + { -0.3223f, 0.1348f, 0.0146f, -0.0894f }, + { -0.2363f, -0.0449f, 0.0586f, 0.0576f }, + { -0.1074f, 0.0898f, 0.0439f, -0.0264f }, + { -0.5801f, -0.0225f, 0.0000f, 0.0576f }, + { -0.4941f, 0.2246f, -0.0879f, 0.0156f }, + { -0.3652f, 0.0000f, 0.0146f, 0.1626f }, + { -0.2793f, 0.1797f, -0.0293f, 0.0996f }, + { -0.1074f, -0.1187f, -0.0552f, -0.0703f }, + { 0.0098f, 0.0059f, -0.0186f, -0.0879f }, + { 0.0879f, -0.1934f, 0.0059f, 0.0703f }, + { 0.1660f, -0.0439f, -0.0430f, 0.0000f }, + { -0.2246f, -0.0938f, -0.0674f, 0.0352f }, + { -0.1855f, 0.1304f, -0.0918f, 0.0352f }, + { -0.0684f, -0.0938f, -0.0186f, 0.1758f }, + { 0.0098f, 0.0557f, -0.0796f, 0.1055f }, + { -0.2637f, -0.2432f, 0.0547f, -0.0352f }, + { -0.1855f, -0.0190f, 0.0303f, -0.0879f }, + { -0.0684f, -0.2432f, 0.0913f, 0.0527f }, + { -0.0293f, -0.0688f, 0.0303f, -0.0176f }, + { -0.4199f, -0.2432f, -0.0063f, 0.0703f }, + { -0.3418f, 0.0308f, -0.0430f, 0.0176f }, + { -0.2246f, -0.1934f, 0.0181f, 0.1758f }, + { -0.1465f, 0.0059f, -0.0674f, 0.0879f }, + { -0.0210f, 0.0483f, 0.0996f, -0.0254f }, + { 0.0210f, 0.3276f, 0.0830f, -0.0454f }, + { 0.0630f, 0.0913f, 0.1328f, 0.0947f }, + { 0.1890f, 0.2417f, 0.1494f, 0.0747f }, + { -0.1890f, 0.1558f, 0.0332f, 0.0547f }, + { -0.1470f, 0.3491f, -0.0166f, 0.0747f }, + { -0.0210f, 0.1128f, 0.0664f, 0.2148f }, + { 0.0630f, 0.2632f, 0.0166f, 0.1348f }, + { -0.2729f, 0.0269f, 0.1992f, -0.0654f }, + { -0.1470f, 0.1987f, 0.1328f, -0.0854f }, + { -0.1050f, 0.0483f, 0.2324f, 0.0547f }, + { 0.0210f, 0.1772f, 0.1826f, 0.0146f }, + { -0.4409f, 0.0913f, 0.1494f, -0.0054f }, + { -0.3569f, 0.3062f, 0.0996f, 0.0146f }, + { -0.2729f, 0.1128f, 0.1328f, 0.1348f }, + { -0.1050f, 0.2202f, 0.0996f, 0.0947f }, + { 0.0767f, -0.0728f, 0.0762f, -0.0498f }, + { 0.1206f, 0.1206f, 0.1230f, -0.0996f }, + { 0.2085f, -0.1050f, 0.1113f, 0.0996f }, + { 0.3403f, 0.0400f, 0.1230f, 0.0498f }, + { -0.0991f, -0.0083f, 0.0645f, 0.0498f }, + { -0.0552f, 0.1206f, 0.0293f, 0.0249f }, + { 0.0767f, -0.0405f, 0.0410f, 0.1992f }, + { 0.1646f, 0.1045f, 0.0410f, 0.1245f }, + { -0.1431f, -0.1211f, 0.1699f, -0.0498f }, + { -0.0991f, 0.0400f, 0.1582f, -0.1743f }, + { 0.0327f, -0.1050f, 0.2051f, 0.0498f }, + { 0.1646f, -0.0083f, 0.1934f, -0.0249f }, + { -0.3188f, -0.1050f, 0.1699f, 0.0747f }, + { -0.1870f, 0.0562f, 0.0996f, 0.0000f }, + { -0.0991f, -0.0566f, 0.1465f, 0.1743f }, + { -0.0112f, 0.0562f, 0.0762f, 0.0996f }, +}; + +/*! \brief HOC 4th block Difference vector quantization table */ +const float ir77_ambe_hoc3_dif_vq[8][4] = { + { 0.1914f, -0.0171f, 0.0103f, 0.0044f }, + { 0.0479f, -0.0718f, -0.0645f, 0.0220f }, + { 0.0239f, -0.0444f, 0.0601f, -0.0366f }, + { -0.0957f, -0.0991f, -0.0063f, 0.0044f }, + { 0.0718f, 0.1060f, -0.0063f, -0.0073f }, + { -0.0479f, 0.0376f, -0.0645f, -0.0190f }, + { -0.0239f, 0.0513f, 0.0601f, 0.0513f }, + { -0.1675f, 0.0376f, 0.0103f, -0.0015f }, +}; + +/*! @} */ diff --git a/codec/tone.c b/codec/tone.c new file mode 100644 index 0000000..601082f --- /dev/null +++ b/codec/tone.c @@ -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; +} + +/*! @} */ |