From 97908aa605f3381906eb48df4d267be3e058b063 Mon Sep 17 00:00:00 2001 From: Patrick W3AXL Date: Wed, 29 Jan 2025 13:41:08 -0500 Subject: [PATCH] initial commit, vocoder compiles pulled in everything referenced from dvmhost/common as a local copy --- .gitignore | 3 + CMakeLists.txt | 21 + vocoder/AMBEFEC.cpp | 601 ++++++++++ vocoder/AMBEFEC.h | 529 +++++++++ vocoder/CMakeLists.txt | 19 + vocoder/Defines.h | 312 +++++ vocoder/Golay24128.cpp | 1256 +++++++++++++++++++++ vocoder/Golay24128.h | 97 ++ vocoder/Hamming.cpp | 362 ++++++ vocoder/Hamming.h | 108 ++ vocoder/MBEDecoder.cpp | 316 ++++++ vocoder/MBEDecoder.h | 141 +++ vocoder/MBEEncoder.cpp | 718 ++++++++++++ vocoder/MBEEncoder.h | 84 ++ vocoder/Utils.cpp | 254 +++++ vocoder/Utils.h | 432 +++++++ vocoder/ambe3600x2250.c | 404 +++++++ vocoder/ambe3600x2400.c | 656 +++++++++++ vocoder/ambe3600x2400_const.h | 903 +++++++++++++++ vocoder/ambe3600x2450.c | 600 ++++++++++ vocoder/ambe3600x2450_const.h | 991 ++++++++++++++++ vocoder/ecc.c | 179 +++ vocoder/ecc_const.h | 124 ++ vocoder/imbe/aux_sub.cpp | 183 +++ vocoder/imbe/aux_sub.h | 134 +++ vocoder/imbe/basic_op.cpp | 2008 +++++++++++++++++++++++++++++++++ vocoder/imbe/basic_op.h | 82 ++ vocoder/imbe/ch_decode.cpp | 178 +++ vocoder/imbe/ch_decode.h | 39 + vocoder/imbe/ch_encode.cpp | 106 ++ vocoder/imbe/ch_encode.h | 36 + vocoder/imbe/dc_rmv.cpp | 67 ++ vocoder/imbe/dc_rmv.h | 48 + vocoder/imbe/decode.cpp | 65 ++ vocoder/imbe/dsp_sub.cpp | 260 +++++ vocoder/imbe/encode.cpp | 91 ++ vocoder/imbe/globals.h | 66 ++ vocoder/imbe/imbe.h | 70 ++ vocoder/imbe/imbe_vocoder.cpp | 63 ++ vocoder/imbe/imbe_vocoder.h | 117 ++ vocoder/imbe/math_sub.cpp | 345 ++++++ vocoder/imbe/math_sub.h | 136 +++ vocoder/imbe/pe_lpf.cpp | 78 ++ vocoder/imbe/pe_lpf.h | 48 + vocoder/imbe/pitch_est.cpp | 330 ++++++ vocoder/imbe/pitch_est.h | 31 + vocoder/imbe/pitch_ref.cpp | 159 +++ vocoder/imbe/pitch_ref.h | 30 + vocoder/imbe/qnt_sub.cpp | 143 +++ vocoder/imbe/qnt_sub.h | 91 ++ vocoder/imbe/rand_gen.cpp | 66 ++ vocoder/imbe/rand_gen.h | 45 + vocoder/imbe/sa_decode.cpp | 187 +++ vocoder/imbe/sa_encode.cpp | 257 +++++ vocoder/imbe/sa_enh.cpp | 188 +++ vocoder/imbe/sa_enh.h | 54 + vocoder/imbe/tbls.cpp | 371 ++++++ vocoder/imbe/tbls.h | 100 ++ vocoder/imbe/typedef.h | 71 ++ vocoder/imbe/typedefs.h | 198 ++++ vocoder/imbe/uv_synt.cpp | 133 +++ vocoder/imbe/v_synt.cpp | 229 ++++ vocoder/imbe/v_uv_det.cpp | 356 ++++++ vocoder/imbe7200x4400.c | 490 ++++++++ vocoder/imbe7200x4400_const.h | 920 +++++++++++++++ vocoder/mbe.c | 477 ++++++++ vocoder/mbe.h | 474 ++++++++ vocoder/mbe_const.h | 390 +++++++ 68 files changed, 19120 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 vocoder/AMBEFEC.cpp create mode 100644 vocoder/AMBEFEC.h create mode 100644 vocoder/CMakeLists.txt create mode 100644 vocoder/Defines.h create mode 100644 vocoder/Golay24128.cpp create mode 100644 vocoder/Golay24128.h create mode 100644 vocoder/Hamming.cpp create mode 100644 vocoder/Hamming.h create mode 100644 vocoder/MBEDecoder.cpp create mode 100644 vocoder/MBEDecoder.h create mode 100644 vocoder/MBEEncoder.cpp create mode 100644 vocoder/MBEEncoder.h create mode 100644 vocoder/Utils.cpp create mode 100644 vocoder/Utils.h create mode 100644 vocoder/ambe3600x2250.c create mode 100644 vocoder/ambe3600x2400.c create mode 100644 vocoder/ambe3600x2400_const.h create mode 100644 vocoder/ambe3600x2450.c create mode 100644 vocoder/ambe3600x2450_const.h create mode 100644 vocoder/ecc.c create mode 100644 vocoder/ecc_const.h create mode 100644 vocoder/imbe/aux_sub.cpp create mode 100644 vocoder/imbe/aux_sub.h create mode 100644 vocoder/imbe/basic_op.cpp create mode 100644 vocoder/imbe/basic_op.h create mode 100644 vocoder/imbe/ch_decode.cpp create mode 100644 vocoder/imbe/ch_decode.h create mode 100644 vocoder/imbe/ch_encode.cpp create mode 100644 vocoder/imbe/ch_encode.h create mode 100644 vocoder/imbe/dc_rmv.cpp create mode 100644 vocoder/imbe/dc_rmv.h create mode 100644 vocoder/imbe/decode.cpp create mode 100644 vocoder/imbe/dsp_sub.cpp create mode 100644 vocoder/imbe/encode.cpp create mode 100644 vocoder/imbe/globals.h create mode 100644 vocoder/imbe/imbe.h create mode 100644 vocoder/imbe/imbe_vocoder.cpp create mode 100644 vocoder/imbe/imbe_vocoder.h create mode 100644 vocoder/imbe/math_sub.cpp create mode 100644 vocoder/imbe/math_sub.h create mode 100644 vocoder/imbe/pe_lpf.cpp create mode 100644 vocoder/imbe/pe_lpf.h create mode 100644 vocoder/imbe/pitch_est.cpp create mode 100644 vocoder/imbe/pitch_est.h create mode 100644 vocoder/imbe/pitch_ref.cpp create mode 100644 vocoder/imbe/pitch_ref.h create mode 100644 vocoder/imbe/qnt_sub.cpp create mode 100644 vocoder/imbe/qnt_sub.h create mode 100644 vocoder/imbe/rand_gen.cpp create mode 100644 vocoder/imbe/rand_gen.h create mode 100644 vocoder/imbe/sa_decode.cpp create mode 100644 vocoder/imbe/sa_encode.cpp create mode 100644 vocoder/imbe/sa_enh.cpp create mode 100644 vocoder/imbe/sa_enh.h create mode 100644 vocoder/imbe/tbls.cpp create mode 100644 vocoder/imbe/tbls.h create mode 100644 vocoder/imbe/typedef.h create mode 100644 vocoder/imbe/typedefs.h create mode 100644 vocoder/imbe/uv_synt.cpp create mode 100644 vocoder/imbe/v_synt.cpp create mode 100644 vocoder/imbe/v_uv_det.cpp create mode 100644 vocoder/imbe7200x4400.c create mode 100644 vocoder/imbe7200x4400_const.h create mode 100644 vocoder/mbe.c create mode 100644 vocoder/mbe.h create mode 100644 vocoder/mbe_const.h diff --git a/.gitignore b/.gitignore index 259148f..f6d6c4c 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,6 @@ *.exe *.out *.app + +# Build directory +build/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..28f4805 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-only +#/* +# * Digital Voice Modem Shared Vocoder - CMake Build System +# * GPLv2 Open Source. Use is subject to license terms. +# * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# * +# * Copyright (C) 2024 Bryan Biedenkapp, N2PLL +# * Copyright (C) 2025 Patrick McDonnell, W3AXL +# * +# */ + +cmake_minimum_required(VERSION 3.16.0) + +project(dvmvocoder) + +# +# Build Vocoder as a Shared Library (dll or so) +# +include(vocoder/CMakeLists.txt) +add_library(vocoder SHARED ${vocoder_SRC} ${vocoder_INCLUDE}) +target_include_directories(vocoder PRIVATE vocoder) \ No newline at end of file diff --git a/vocoder/AMBEFEC.cpp b/vocoder/AMBEFEC.cpp new file mode 100644 index 0000000..b8e6dd5 --- /dev/null +++ b/vocoder/AMBEFEC.cpp @@ -0,0 +1,601 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - Common Library + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright (C) 2010,2014,2016,2021 Jonathan Naylor, G4KLX + * Copyright (C) 2016 Mathias Weyland, HB9FRV + * Copyright (C) 2018-2022 Bryan Biedenkapp, N2PLL + * + */ +#include "Defines.h" +#include "AMBEFEC.h" +#include "Golay24128.h" +#include "Hamming.h" +#include "Utils.h" + +using namespace edac; + +#include +#include + +// --------------------------------------------------------------------------- +// Public Class Members +// --------------------------------------------------------------------------- + +/* Initializes a new instance of the AMBEFEC class. */ + +AMBEFEC::AMBEFEC() = default; + +/* Finalizes a instance of the AMBEFEC class. */ + +AMBEFEC::~AMBEFEC() = default; + +/* Regenerates the DMR AMBE FEC for the input bytes. */ + +uint32_t AMBEFEC::regenerateDMR(uint8_t* bytes) const +{ + assert(bytes != nullptr); + + uint32_t a1 = 0U, a2 = 0U, a3 = 0U; + uint32_t b1 = 0U, b2 = 0U, b3 = 0U; + uint32_t c1 = 0U, c2 = 0U, c3 = 0U; + + uint32_t MASK = 0x800000U; + for (uint32_t i = 0U; i < 24U; i++, MASK >>= 1) { + uint32_t a1Pos = AMBE_A_TABLE[i]; + uint32_t a2Pos = a1Pos + 72U; + if (a2Pos >= 108U) + a2Pos += 48U; + uint32_t a3Pos = a1Pos + 192U; + + if (READ_BIT(bytes, a1Pos)) + a1 |= MASK; + if (READ_BIT(bytes, a2Pos)) + a2 |= MASK; + if (READ_BIT(bytes, a3Pos)) + a3 |= MASK; + } + + MASK = 0x400000U; + for (uint32_t i = 0U; i < 23U; i++, MASK >>= 1) { + uint32_t b1Pos = AMBE_B_TABLE[i]; + uint32_t b2Pos = b1Pos + 72U; + if (b2Pos >= 108U) + b2Pos += 48U; + uint32_t b3Pos = b1Pos + 192U; + + if (READ_BIT(bytes, b1Pos)) + b1 |= MASK; + if (READ_BIT(bytes, b2Pos)) + b2 |= MASK; + if (READ_BIT(bytes, b3Pos)) + b3 |= MASK; + } + + MASK = 0x1000000U; + for (uint32_t i = 0U; i < 25U; i++, MASK >>= 1) { + uint32_t c1Pos = AMBE_C_TABLE[i]; + uint32_t c2Pos = c1Pos + 72U; + if (c2Pos >= 108U) + c2Pos += 48U; + uint32_t c3Pos = c1Pos + 192U; + + if (READ_BIT(bytes, c1Pos)) + c1 |= MASK; + if (READ_BIT(bytes, c2Pos)) + c2 |= MASK; + if (READ_BIT(bytes, c3Pos)) + c3 |= MASK; + } + + uint32_t errors = regenerate(a1, b1, c1); + errors += regenerate(a2, b2, c2); + errors += regenerate(a3, b3, c3); + + MASK = 0x800000U; + for (uint32_t i = 0U; i < 24U; i++, MASK >>= 1) { + uint32_t a1Pos = AMBE_A_TABLE[i]; + uint32_t a2Pos = a1Pos + 72U; + if (a2Pos >= 108U) + a2Pos += 48U; + uint32_t a3Pos = a1Pos + 192U; + + WRITE_BIT(bytes, a1Pos, a1 & MASK); + WRITE_BIT(bytes, a2Pos, a2 & MASK); + WRITE_BIT(bytes, a3Pos, a3 & MASK); + } + + MASK = 0x400000U; + for (uint32_t i = 0U; i < 23U; i++, MASK >>= 1) { + uint32_t b1Pos = AMBE_B_TABLE[i]; + uint32_t b2Pos = b1Pos + 72U; + if (b2Pos >= 108U) + b2Pos += 48U; + uint32_t b3Pos = b1Pos + 192U; + + WRITE_BIT(bytes, b1Pos, b1 & MASK); + WRITE_BIT(bytes, b2Pos, b2 & MASK); + WRITE_BIT(bytes, b3Pos, b3 & MASK); + } + + MASK = 0x1000000U; + for (uint32_t i = 0U; i < 25U; i++, MASK >>= 1) { + uint32_t c1Pos = AMBE_C_TABLE[i]; + uint32_t c2Pos = c1Pos + 72U; + if (c2Pos >= 108U) + c2Pos += 48U; + uint32_t c3Pos = c1Pos + 192U; + + WRITE_BIT(bytes, c1Pos, c1 & MASK); + WRITE_BIT(bytes, c2Pos, c2 & MASK); + WRITE_BIT(bytes, c3Pos, c3 & MASK); + } + + return errors; +} + +/* Returns the number of errors on the DMR BER input bytes. */ + +uint32_t AMBEFEC::measureDMRBER(const uint8_t* bytes) const +{ + assert(bytes != nullptr); + + uint32_t a1 = 0U, a2 = 0U, a3 = 0U; + uint32_t b1 = 0U, b2 = 0U, b3 = 0U; + uint32_t c1 = 0U, c2 = 0U, c3 = 0U; + + uint32_t MASK = 0x800000U; + for (uint32_t i = 0U; i < 24U; i++, MASK >>= 1) { + uint32_t a1Pos = AMBE_A_TABLE[i]; + uint32_t a2Pos = a1Pos + 72U; + if (a2Pos >= 108U) + a2Pos += 48U; + uint32_t a3Pos = a1Pos + 192U; + + if (READ_BIT(bytes, a1Pos)) + a1 |= MASK; + if (READ_BIT(bytes, a2Pos)) + a2 |= MASK; + if (READ_BIT(bytes, a3Pos)) + a3 |= MASK; + } + + MASK = 0x400000U; + for (uint32_t i = 0U; i < 23U; i++, MASK >>= 1) { + uint32_t b1Pos = AMBE_B_TABLE[i]; + uint32_t b2Pos = b1Pos + 72U; + if (b2Pos >= 108U) + b2Pos += 48U; + uint32_t b3Pos = b1Pos + 192U; + + if (READ_BIT(bytes, b1Pos)) + b1 |= MASK; + if (READ_BIT(bytes, b2Pos)) + b2 |= MASK; + if (READ_BIT(bytes, b3Pos)) + b3 |= MASK; + } + + MASK = 0x1000000U; + for (uint32_t i = 0U; i < 25U; i++, MASK >>= 1) { + uint32_t c1Pos = AMBE_C_TABLE[i]; + uint32_t c2Pos = c1Pos + 72U; + if (c2Pos >= 108U) + c2Pos += 48U; + uint32_t c3Pos = c1Pos + 192U; + + if (READ_BIT(bytes, c1Pos)) + c1 |= MASK; + if (READ_BIT(bytes, c2Pos)) + c2 |= MASK; + if (READ_BIT(bytes, c3Pos)) + c3 |= MASK; + } + + uint32_t errors = regenerate(a1, b1, c1); + errors += regenerate(a2, b2, c2); + errors += regenerate(a3, b3, c3); + + return errors; +} + +/* Regenerates the P25 IMBE FEC for the input bytes. */ + +uint32_t AMBEFEC::regenerateIMBE(uint8_t* bytes) const +{ + assert(bytes != nullptr); + + bool orig[144U]; + bool temp[144U]; + + // De-interleave + for (uint32_t i = 0U; i < 144U; i++) { + uint32_t n = IMBE_INTERLEAVE[i]; + orig[i] = temp[i] = READ_BIT(bytes, n); + } + + // now .. + + // 12 voice bits 0 + // 11 golay bits 12 + // + // 12 voice bits 23 + // 11 golay bits 35 + // + // 12 voice bits 46 + // 11 golay bits 58 + // + // 12 voice bits 69 + // 11 golay bits 81 + // + // 11 voice bits 92 + // 4 hamming bits 103 + // + // 11 voice bits 107 + // 4 hamming bits 118 + // + // 11 voice bits 122 + // 4 hamming bits 133 + // + // 7 voice bits 137 + + // Process the c0 section first to allow the de-whitening to be accurate + + // Check/Fix FEC + bool* bit = temp; + + // c0 + uint32_t g1 = 0U; + for (uint32_t i = 0U; i < 23U; i++) + g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U); + uint32_t c0data = Golay24128::decode23127(g1); + uint32_t g2 = Golay24128::encode23127(c0data); + for (int i = 23; i >= 0; i--) { + bit[i] = (g2 & 0x01U) == 0x01U; + g2 >>= 1; + } + bit += 23U; + + bool prn[114U]; + + // Create the whitening vector and save it for future use + uint32_t p = 16U * c0data; + for (uint32_t i = 0U; i < 114U; i++) { + p = (173U * p + 13849U) % 65536U; + prn[i] = p >= 32768U; + } + + // De-whiten some bits + for (uint32_t i = 0U; i < 114U; i++) + temp[i + 23U] ^= prn[i]; + + // c1 + g1 = 0U; + for (uint32_t i = 0U; i < 23U; i++) + g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U); + uint32_t c1data = Golay24128::decode23127(g1); + g2 = Golay24128::encode23127(c1data); + for (int i = 23; i >= 0; i--) { + bit[i] = (g2 & 0x01U) == 0x01U; + g2 >>= 1; + } + bit += 23U; + + // c2 + g1 = 0; + for (uint32_t i = 0U; i < 23U; i++) + g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U); + uint32_t c2data = Golay24128::decode23127(g1); + g2 = Golay24128::encode23127(c2data); + for (int i = 23; i >= 0; i--) { + bit[i] = (g2 & 0x01U) == 0x01U; + g2 >>= 1; + } + bit += 23U; + + // c3 + g1 = 0U; + for (uint32_t i = 0U; i < 23U; i++) + g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U); + uint32_t c3data = Golay24128::decode23127(g1); + g2 = Golay24128::encode23127(c3data); + for (int i = 23; i >= 0; i--) { + bit[i] = (g2 & 0x01U) == 0x01U; + g2 >>= 1; + } + bit += 23U; + + // c4 + Hamming::decode15113_1(bit); + bit += 15U; + + // c5 + Hamming::decode15113_1(bit); + bit += 15U; + + // c6 + Hamming::decode15113_1(bit); + + // Whiten some bits + for (uint32_t i = 0U; i < 114U; i++) + temp[i + 23U] ^= prn[i]; + + uint32_t errors = 0U; + for (uint32_t i = 0U; i < 144U; i++) { + if (orig[i] != temp[i]) + errors++; + } + + // Interleave + for (uint32_t i = 0U; i < 144U; i++) { + uint32_t n = IMBE_INTERLEAVE[i]; + WRITE_BIT(bytes, n, temp[i]); + } + + return errors; +} + +/* Returns the number of errors on the P25 BER input bytes. */ + +uint32_t AMBEFEC::measureP25BER(const uint8_t* bytes) const +{ + assert(bytes != nullptr); + + bool orig[144U]; + bool temp[144U]; + + // De-interleave + for (uint32_t i = 0U; i < 144U; i++) { + uint32_t n = IMBE_INTERLEAVE[i]; + orig[i] = temp[i] = READ_BIT(bytes, n); + } + + // now .. + + // 12 voice bits 0 + // 11 golay bits 12 + // + // 12 voice bits 23 + // 11 golay bits 35 + // + // 12 voice bits 46 + // 11 golay bits 58 + // + // 12 voice bits 69 + // 11 golay bits 81 + // + // 11 voice bits 92 + // 4 hamming bits 103 + // + // 11 voice bits 107 + // 4 hamming bits 118 + // + // 11 voice bits 122 + // 4 hamming bits 133 + // + // 7 voice bits 137 + + // Process the c0 section first to allow the de-whitening to be accurate + + // Check/Fix FEC + bool* bit = temp; + + // c0 + uint32_t g1 = 0U; + for (uint32_t i = 0U; i < 23U; i++) + g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U); + uint32_t c0data = Golay24128::decode23127(g1); + uint32_t g2 = Golay24128::encode23127(c0data); + for (int i = 23; i >= 0; i--) { + bit[i] = (g2 & 0x01U) == 0x01U; + g2 >>= 1; + } + bit += 23U; + + bool prn[114U]; + + // Create the whitening vector and save it for future use + uint32_t p = 16U * c0data; + for (uint32_t i = 0U; i < 114U; i++) { + p = (173U * p + 13849U) % 65536U; + prn[i] = p >= 32768U; + } + + // De-whiten some bits + for (uint32_t i = 0U; i < 114U; i++) + temp[i + 23U] ^= prn[i]; + + // c1 + g1 = 0U; + for (uint32_t i = 0U; i < 23U; i++) + g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U); + uint32_t c1data = Golay24128::decode23127(g1); + g2 = Golay24128::encode23127(c1data); + for (int i = 23; i >= 0; i--) { + bit[i] = (g2 & 0x01U) == 0x01U; + g2 >>= 1; + } + bit += 23U; + + // c2 + g1 = 0; + for (uint32_t i = 0U; i < 23U; i++) + g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U); + uint32_t c2data = Golay24128::decode23127(g1); + g2 = Golay24128::encode23127(c2data); + for (int i = 23; i >= 0; i--) { + bit[i] = (g2 & 0x01U) == 0x01U; + g2 >>= 1; + } + bit += 23U; + + // c3 + g1 = 0U; + for (uint32_t i = 0U; i < 23U; i++) + g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U); + uint32_t c3data = Golay24128::decode23127(g1); + g2 = Golay24128::encode23127(c3data); + for (int i = 23; i >= 0; i--) { + bit[i] = (g2 & 0x01U) == 0x01U; + g2 >>= 1; + } + bit += 23U; + + // c4 + Hamming::decode15113_1(bit); + bit += 15U; + + // c5 + Hamming::decode15113_1(bit); + bit += 15U; + + // c6 + Hamming::decode15113_1(bit); + + // Whiten some bits + for (uint32_t i = 0U; i < 114U; i++) + temp[i + 23U] ^= prn[i]; + + uint32_t errors = 0U; + for (uint32_t i = 0U; i < 144U; i++) { + if (orig[i] != temp[i]) + errors++; + } + + return errors; +} + +/* Regenerates the NXDN AMBE FEC for the input bytes. */ + +uint32_t AMBEFEC::regenerateNXDN(uint8_t* bytes) const +{ + assert(bytes != nullptr); + + uint32_t a = 0U; + uint32_t MASK = 0x800000U; + for (uint32_t i = 0U; i < 24U; i++, MASK >>= 1) { + uint32_t aPos = AMBE_A_TABLE[i]; + if (READ_BIT(bytes, aPos)) + a |= MASK; + } + + uint32_t b = 0U; + MASK = 0x400000U; + for (uint32_t i = 0U; i < 23U; i++, MASK >>= 1) { + uint32_t bPos = AMBE_B_TABLE[i]; + if (READ_BIT(bytes, bPos)) + b |= MASK; + } + + uint32_t c = 0U; + MASK = 0x1000000U; + for (uint32_t i = 0U; i < 25U; i++, MASK >>= 1) { + uint32_t cPos = AMBE_C_TABLE[i]; + if (READ_BIT(bytes, cPos)) + c |= MASK; + } + + uint32_t errors = regenerate(a, b, c); + + MASK = 0x800000U; + for (uint32_t i = 0U; i < 24U; i++, MASK >>= 1) { + uint32_t aPos = AMBE_A_TABLE[i]; + WRITE_BIT(bytes, aPos, a & MASK); + } + + MASK = 0x400000U; + for (uint32_t i = 0U; i < 23U; i++, MASK >>= 1) { + uint32_t bPos = AMBE_B_TABLE[i]; + WRITE_BIT(bytes, bPos, b & MASK); + } + + MASK = 0x1000000U; + for (uint32_t i = 0U; i < 25U; i++, MASK >>= 1) { + uint32_t cPos = AMBE_C_TABLE[i]; + WRITE_BIT(bytes, cPos, c & MASK); + } + + return errors; +} + +/* Returns the number of errors on the NXDN BER input bytes. */ + +uint32_t AMBEFEC::measureNXDNBER(uint8_t* bytes) const +{ + assert(bytes != nullptr); + + uint32_t a = 0U; + uint32_t MASK = 0x800000U; + for (uint32_t i = 0U; i < 24U; i++, MASK >>= 1) { + uint32_t aPos = AMBE_A_TABLE[i]; + if (READ_BIT(bytes, aPos)) + a |= MASK; + } + + uint32_t b = 0U; + MASK = 0x400000U; + for (uint32_t i = 0U; i < 23U; i++, MASK >>= 1) { + uint32_t bPos = AMBE_B_TABLE[i]; + if (READ_BIT(bytes, bPos)) + b |= MASK; + } + + uint32_t c = 0U; + MASK = 0x1000000U; + for (uint32_t i = 0U; i < 25U; i++, MASK >>= 1) { + uint32_t cPos = AMBE_C_TABLE[i]; + if (READ_BIT(bytes, cPos)) + c |= MASK; + } + + uint32_t errors = regenerate(a, b, c); + return errors; +} + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- + +/* */ + +uint32_t AMBEFEC::regenerate(uint32_t& a, uint32_t& b, uint32_t& c) const +{ + uint32_t old_a = a; + uint32_t old_b = b; + + uint32_t data; + bool valid = Golay24128::decode24128(a, data); + if (!valid) { + uint32_t errsA = Utils::countBits32(data ^ a); + a = 0xF00292U; + b = 0x0E0B20U; + c = 0x000000U; + return errsA; + } + + a = Golay24128::encode24128(data); + + // PRNG + uint32_t p = PRNG_TABLE[data] >> 1; + b ^= p; + + uint32_t datb = Golay24128::decode23127(b); + b = Golay24128::encode23127(datb) >> 1; + + b ^= p; + + uint32_t v = a ^ old_a; + uint32_t errsA = Utils::countBits32(v); + + v = b ^ old_b; + uint32_t errsB = Utils::countBits32(v); + if (errsA >= 4U || ((errsA + errsB) >= 6U && errsA >= 2U)) { + a = 0xF00292U; + b = 0x0E0B20U; + c = 0x000000U; + } + + return errsA + errsB; +} diff --git a/vocoder/AMBEFEC.h b/vocoder/AMBEFEC.h new file mode 100644 index 0000000..4ba498c --- /dev/null +++ b/vocoder/AMBEFEC.h @@ -0,0 +1,529 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - Common Library + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright (C) 2010,2014,2016,2021 Jonathan Naylor, G4KLX + * Copyright (C) 2018-2022 Bryan Biedenkapp, N2PLL + * + */ +/** + * @file AMBEFEC.h + * @ingroup edac + * @file AMBEFEC.cpp + * @ingroup edac + */ +#if !defined(__AMBE_FEC_H__) +#define __AMBE_FEC_H__ + +#include "Defines.h" + +namespace edac +{ + // --------------------------------------------------------------------------- + // Constants + // --------------------------------------------------------------------------- + + const uint32_t PRNG_TABLE[] = { + 0x42CC47U, 0x19D6FEU, 0x304729U, 0x6B2CD0U, 0x60BF47U, 0x39650EU, 0x7354F1U, 0xEACF60U, 0x819C9FU, 0xDE25CEU, + 0xD7B745U, 0x8CC8B8U, 0x8D592BU, 0xF71257U, 0xBCA084U, 0xA5B329U, 0xEE6AFAU, 0xF7D9A7U, 0xBCC21CU, 0x4712D9U, + 0x4F2922U, 0x14FA37U, 0x5D43ECU, 0x564115U, 0x299A92U, 0x20A9EBU, 0x7B707DU, 0x3BE3A4U, 0x20D95BU, 0x6B085AU, + 0x5233A5U, 0x99A474U, 0xC0EDCBU, 0xCB5F12U, 0x918455U, 0xF897ECU, 0xE32E3BU, 0xAA7CC2U, 0xB1E7C9U, 0xFC561DU, + 0xA70DE6U, 0x8DBE73U, 0xD4F608U, 0x57658DU, 0x0E5E56U, 0x458DABU, 0x7E15B8U, 0x376645U, 0x2DFD86U, 0x64EC3BU, + 0x3F1F60U, 0x3481B4U, 0x4DA00FU, 0x067BCEU, 0x1B68B1U, 0xD19328U, 0xCA03FFU, 0xA31856U, 0xF8EB81U, 0xF9F2F8U, + 0xA26067U, 0xA91BB6U, 0xF19A59U, 0x9A6148U, 0x8372B6U, 0xC8E86FU, 0x9399DCU, 0x1A0291U, 0x619142U, 0x6DE9FFU, + 0x367A2CU, 0x7D2511U, 0x6484DAU, 0x2F1F0FU, 0x1E6DB4U, 0x55F6E1U, 0x0EA70AU, 0x061C96U, 0xDD0E45U, 0xB4D738U, + 0xAF64ABU, 0xE47F42U, 0xFDBE9DU, 0xB684ACU, 0xFE5773U, 0xC1E4A2U, 0x8AFD0DU, 0x932ED4U, 0xD814E3U, 0x81853AU, + 0x225EECU, 0x7A6945U, 0x31A112U, 0x2AB2EBU, 0x630974U, 0x785AB5U, 0x11E3CEU, 0x4A715BU, 0x402AA0U, 0x199B7DU, + 0x16C05EU, 0x6F5283U, 0xA4FB10U, 0xBFA8ECU, 0xF633B7U, 0xEC4012U, 0xADD8C9U, 0xD6EB1CU, 0xDD3027U, 0x84A1FAU, + 0xCF9E19U, 0xD64C80U, 0xBC4557U, 0xA7B62EU, 0x6E2DA1U, 0x311F50U, 0x38C68EU, 0x63D5BFU, 0x486E60U, 0x10BFE1U, + 0x5BAD1EU, 0x4A4647U, 0x0157F0U, 0x7ACC29U, 0x73BEEAU, 0x2825D7U, 0xA0940CU, 0xFBCFF9U, 0xB05C62U, 0x892426U, + 0xC6B3DDU, 0xDF3840U, 0x9449B3U, 0xCED3BEU, 0xE7804DU, 0xBC3B90U, 0xF5AA0BU, 0xE6D17EU, 0x2D43B5U, 0x345A04U, + 0x5EA9DBU, 0x07A202U, 0x0C7134U, 0x45C9FDU, 0x5EDA0AU, 0x310193U, 0x6830C4U, 0x62AA3DU, 0x3B59B2U, 0xB04043U, + 0xEB975CU, 0x82BCADU, 0x912E62U, 0xD8F7FBU, 0x82C489U, 0x895F54U, 0xF00FE7U, 0xFBBC2AU, 0xA2E771U, 0xE956C4U, + 0xF6CD1FU, 0x3F8FEAU, 0x0534E1U, 0x4C653CU, 0x17FE8FU, 0x1C4C52U, 0x4515A1U, 0x2E86A9U, 0x3FBD56U, 0x756C87U, + 0x6ED218U, 0x279179U, 0x7C0AA6U, 0xD53B17U, 0x8EE0C8U, 0x85F291U, 0xD94B36U, 0x9298EFU, 0xAB8318U, 0xE07301U, + 0xBB68DFU, 0xB2CB7CU, 0xE910A5U, 0xE101D2U, 0x92BB4BU, 0x59E8B4U, 0x407175U, 0x0B026AU, 0x12989BU, 0x792944U, + 0x2376EDU, 0x2EF5BAU, 0x758663U, 0x7C1ED5U, 0x078D0CU, 0x4EF6ABU, 0x5567F2U, 0x9F7C29U, 0xC68E9CU, 0xC51747U, + 0xBC6422U, 0xB7EFB9U, 0xECFD44U, 0xA50497U, 0xAF178AU, 0xD68C69U, 0xD97DB5U, 0x82670EU, 0xCBB45BU, 0x508D90U, + 0x190A25U, 0x63F0FEU, 0x68E3C7U, 0x317A10U, 0x3A09D9U, 0x6B926EU, 0x004237U, 0x1B79C8U, 0x53EA59U, 0x48B3B7U, + 0x811166U, 0xDE4A79U, 0xF5F988U, 0xAC6057U, 0xE733FEU, 0xFF89ADU, 0xB49830U, 0x8F4BC3U, 0xC6F00EU, 0x9DA135U, + 0x942FE0U, 0xC71C3BU, 0x4DC78FU, 0x3476C4U, 0x7F6C39U, 0x66BFAAU, 0x298657U, 0x725504U, 0x5B4E89U, 0x01FE72U, + 0x0835A3U, 0x53269CU, 0x189D4DU, 0x01CDC2U, 0xEA763BU, 0xF3A56DU, 0xB0BCD4U, 0xE80F13U, 0xE355CAU, 0x98C47DU, + 0x91AB24U, 0xCE38DBU, 0x87A35AU, 0x9CD3A5U, 0xD648F4U, 0xAF7B6FU, 0x24A292U, 0x7D3011U, 0x764B6DU, 0x2DDABEU, + 0x44D123U, 0x5E22D8U, 0x1FB09DU, 0x04A926U, 0x4F5AF3U, 0x064128U, 0x3DB105U, 0x70AAD6U, 0xAA392FU, 0xA1C4B8U, + 0xF8C7C0U, 0xD35D0FU, 0x8A2E9EU, 0xC1B761U, 0xDA44F0U, 0x925E8FU, 0x89CF4EU, 0xE8B4D1U, 0xB32728U, 0xB8FE7FU, + 0x61DCC6U, 0x2A4701U, 0x1614D8U, 0x5DADE2U, 0x46BE37U, 0x0F44DCU, 0x54D549U, 0x5D8E32U, 0x263DAFU, 0x2C237CU, + 0x75E291U, 0xBE5982U, 0xA74A7FU, 0xC493A4U, 0xDFA131U, 0x967A5AU, 0xCCCB8EU, 0xC1D835U, 0x9A02ECU, 0xF331BBU, + 0xE8B812U, 0xA3EBC5U, 0xBA507CU, 0x7080ABU, 0x099BC2U, 0x02285DU, 0x59718CU, 0x50C273U, 0x0B1862U, 0x4A1F8CU, + 0x70A655U, 0x3BF5C2U, 0x666FBBU, 0x6DDE68U, 0x3485C5U, 0x9F161EU, 0xC46F4BU, 0x8CFDF0U, 0x97C625U, 0xDE058EU, + 0xC59CD3U, 0xAEAE20U, 0xF775BCU, 0xFC647FU, 0xBD9F02U, 0xE70C91U, 0xCC1468U, 0x11E7B7U, 0x1AFC36U, 0x435B49U, + 0x080398U, 0x139027U, 0x7B63FEU, 0x607AF9U, 0x29E900U, 0x7293D6U, 0x79026FU, 0x00D930U, 0x0BEAF1U, 0xD3614EU, + 0x90119FU, 0x8B8AE4U, 0xC61969U, 0xBD609AU, 0xB4F247U, 0xEFA954U, 0xE518A9U, 0xBC0362U, 0xD7D0D6U, 0xCE7E8DU, + 0x856F18U, 0x1C94E3U, 0x578726U, 0x0D5F1DU, 0x24ECC0U, 0x7FF713U, 0x3E26AAU, 0x251D6DU, 0x6A8F14U, 0x53648BU, + 0x19757AU, 0x40AEB4U, 0xCB9CA5U, 0x90055AU, 0x9956C3U, 0xE2ED34U, 0xAB3C7DU, 0xB126EAU, 0xFA9513U, 0xA3D2C8U, + 0x886BFDU, 0xD9F836U, 0xD2A2E3U, 0x8D1359U, 0x454804U, 0x5EDBF7U, 0x37637AU, 0x2C3089U, 0x67ABD4U, 0x3E8847U, + 0x3551BAU, 0x4D6331U, 0x46B8C4U, 0x1D299FU, 0x54120EU, 0x5FC0E1U, 0x86D93BU, 0xE56A0EU, 0xFBB1D5U, 0xB2B600U, + 0xA94EABU, 0xE05DF6U, 0x9BE605U, 0x90B798U, 0xC92C6BU, 0xC3DE66U, 0x9AC7BDU, 0xD15448U, 0x6A3FD3U, 0x23ADA3U, + 0x78346CU, 0x7147F5U, 0x2BDC02U, 0x0EAD5BU, 0x553FFCU, 0x1EA425U, 0x07D5F2U, 0x4C4ECBU, 0x554C14U, 0x3EB3F5U, + 0xE4A26AU, 0xED799BU, 0xB6CA85U, 0xFFD25CU, 0xC421BFU, 0x8F3A22U, 0x96AB51U, 0xDC518CU, 0x895217U, 0x8289F2U, + 0xF9B8A9U, 0xF0231CU, 0x2BF1C7U, 0x62C80AU, 0x781B39U, 0x1320E5U, 0x4AB156U, 0x41EB8FU, 0x1848E0U, 0x13D771U, + 0x4886AEU, 0x203C5FU, 0x3B6F40U, 0x76F6A1U, 0xE5457EU, 0xAE1EE7U, 0xD7AC10U, 0xDCB549U, 0x8476EFU, 0x8FC536U, + 0xD49DE9U, 0x9D0ED8U, 0xA63513U, 0xEFE4A6U, 0xB4DF7DU, 0x3E0D00U, 0x779693U, 0x4CA75EU, 0x0568ADU, 0x527BB0U, + 0x59C34BU, 0x00109FU, 0x0A0B14U, 0x73FA61U, 0x38E0BAU, 0x23530FU, 0x6A88D4U, 0xB199DDU, 0x98322AU, 0xC260F3U, + 0xCBF944U, 0x908A0DU, 0xDB11F2U, 0xC28163U, 0xADFABDU, 0xBC694CU, 0xF65243U, 0xAD83BAU, 0xA40D6DU, 0x5F7EF4U, + 0x16E787U, 0x0DF44AU, 0x460EF1U, 0x5E1F24U, 0x15CC3FU, 0x6C77CAU, 0x676401U, 0x3C9CBDU, 0x359FEEU, 0x6A0413U, + 0x02F590U, 0x91EE4DU, 0xDA3C3EU, 0xC305A3U, 0x889658U, 0xF14D99U, 0xFA7F86U, 0xA1E677U, 0xE981E8U, 0xF21A10U, + 0xBB4BD7U, 0x80F1CEU, 0xCB6239U, 0x123BE0U, 0x1D885FU, 0x45921EU, 0x6641E1U, 0x3DE870U, 0x74BBAFU, 0x6F00C6U, + 0x261055U, 0x7DCBA8U, 0x57787AU, 0x0E2167U, 0x05B28CU, 0xCC8819U, 0x975BE2U, 0xBC52B7U, 0xE5E52CU, 0xEB37C9U, + 0xB20E12U, 0xF9DD2FU, 0xE8C6FCU, 0x837701U, 0xD8AD82U, 0xD1BE5AU, 0x0B0525U, 0x0244B4U, 0x79FE5BU, 0x322DCAU, + 0x2B3495U, 0x60876CU, 0x79DCFBU, 0x334C12U, 0x4C7745U, 0x45A4DCU, 0x1E3F23U, 0x175FF2U, 0xC4C0D8U, 0xAFF30DU, + 0xB72AF6U, 0xFCB96BU, 0xA5C338U, 0xAE5295U, 0xF54946U, 0xDCBABBU, 0x87A1A8U, 0xCF2165U, 0xD4DA9EU, 0x9FC90BU, + 0x223070U, 0x6922A4U, 0x30B92FU, 0x3348D6U, 0x695B01U, 0x20C038U, 0x1BB2EFU, 0x523B06U, 0x49EC99U, 0x02D7C8U, + 0x5B4777U, 0x713CA6U, 0xA8AF49U, 0xA3B650U, 0xF84586U, 0xB5DF7FU, 0xAE8CF8U, 0xC72581U, 0x9D3652U, 0x9EEDCFU, + 0xC75D34U, 0xCC0671U, 0xB5B5CAU, 0xFEAC1FU, 0x677EA4U, 0x2DC5F9U, 0x26D63AU, 0x7F1F86U, 0x142855U, 0x0DF2A8U, + 0x42E3B3U, 0x195872U, 0x108B8DU, 0x6AB31CU, 0x632063U, 0x307BAAU, 0xFBC83DU, 0xE201C4U, 0xA91393U, 0x90A82AU, + 0xDAF9E4U, 0x816A55U, 0x88D00AU, 0xD383DBU, 0xFA3A64U, 0xA569A5U, 0xEEE2DEU, 0x76D243U, 0x3D0D90U, 0x649E6DU, + 0x47E76EU, 0x1C7491U, 0x156E49U, 0x4E9DDEU, 0x0604B7U, 0x3D3720U, 0x76FDD9U, 0x6FEC06U, 0x2417B7U, 0xFD04F8U, + 0xF29D29U, 0x886F92U, 0xC1744FU, 0xDAC73CU, 0x939EB1U, 0x880C63U, 0xEBE79EU, 0xB2F285U, 0xB86970U, 0xE11ABBU, + 0xEA822EU, 0x311155U, 0x586AC0U, 0x43F92BU, 0x0A81F6U, 0x5412C5U, 0x5D111CU, 0x26E8CBU, 0x2D7B63U, 0x74213CU, + 0x3F90CDU, 0x2E8B52U, 0x645883U, 0xDFE36CU, 0x96F375U, 0xDD0882U, 0xC40B1BU, 0x8FD6CCU, 0xB464A5U, 0xFC7F3EU, + 0xA7AECBU, 0xAA9511U, 0xF10634U, 0xBA5CEFU, 0x83ED32U, 0x483681U, 0x5015DCU, 0x138D3FU, 0x48DEA2U, 0x616571U, + 0x3AF40CU, 0x33AF97U, 0x681D72U, 0x2246E9U, 0x3BD7B9U, 0x506C46U, 0x0D2FDFU, 0x869338U, 0xDDC061U, 0xD45BD6U, + 0xAF6A0FU, 0xE7B8C0U, 0xFC2371U, 0xBF102EU, 0xA6C9DFU, 0xEDDA40U, 0x943089U, 0x9FA1BFU, 0x459A66U, 0x0C4995U, + 0x175108U, 0x7AE243U, 0x6139B6U, 0x2A2A2DU, 0x73D3D8U, 0x79C183U, 0x204A26U, 0x0B3FFDU, 0x5AA420U, 0x111613U, + 0x8A4FDFU, 0xC3DC2CU, 0xF9A7B5U, 0xB034EAU, 0xEBAC5BU, 0xE0CF94U, 0xBD5465U, 0xF605FAU, 0xCFBEA3U, 0x85AC54U, + 0x9E55DDU, 0xD7C62AU, 0x0CDD73U, 0x252FCDU, 0x76361CU, 0x7DF5D3U, 0x3546E2U, 0x6E5B39U, 0x67A98CU, 0x1CB247U, + 0x57231AU, 0x4AD8A9U, 0x01CA74U, 0x191187U, 0xF2208AU, 0xA9AB50U, 0xA0F8A5U, 0xFB403EU, 0xF2D34BU, 0xA9A880U, + 0xCB393DU, 0xD262EEU, 0x99D0B7U, 0xC04B00U, 0xCB1AC9U, 0xB0B176U, 0x39E3A7U, 0x677EF8U, 0x2ECD58U, 0x359687U, + 0x7E277EU, 0x473D69U, 0x0CEEB0U, 0x55D557U, 0x5F04CEU, 0x0C8EBDU, 0x25BD60U, 0x7E64DBU, 0xB7771EU, 0xACCC05U, + 0xE51CF0U, 0xBF2F2AU, 0x90F497U, 0xC9E7D4U, 0xC25F09U, 0x9B9CBAU, 0xD08767U, 0xEB320CU, 0xA36999U, 0x38FB42U, + 0x7180B3U, 0x22112CU, 0x29AA45U, 0x50F9D2U, 0x1B610AU, 0x0202FDU, 0x4899E4U, 0x57080BU, 0x3E72DAU, 0x65E165U, + 0x6CFA34U, 0xB70BEBU, 0xBC104AU, 0xE4E295U, 0x8F7BECU, 0x96787FU, 0xD583B2U, 0x9E9740U, 0x870C5DU, 0xECFFA6U, + 0xF4E433U, 0xBF35F8U, 0xE00F8DU, 0x699C16U, 0x3265EBU, 0x1B6638U, 0x40F515U, 0x0A8DC6U, 0x131E1BU, 0x5845A0U, + 0x21F670U, 0x2A6E1FU, 0x791D8EU, 0x708651U, 0x2AD7E8U, 0xE37CAFU, 0xD8EE56U, 0x97B3C1U, 0x8E0018U, 0xC51B6FU, + 0x9CC9E6U, 0xB67019U, 0xEF23C8U, 0xE498F2U, 0xBF9927U, 0xF643ECU, 0xCD7051U, 0x04E902U, 0x563AFFU, 0x5D006CU, + 0x04D3A1U, 0x0FCA9AU, 0x72794FU, 0x39A2B4U, 0x228231U, 0x6A19EAU, 0x714E96U, 0x18F705U, 0x4324FCU, 0xC83E3BU, + 0x918D02U, 0xDADCD5U, 0xC2470CU, 0xA135B3U, 0xBABCF2U, 0xF30F4DU, 0xA8549EU, 0xA1C543U, 0xDEFF78U, 0xD42CBCU, + 0x0DB747U, 0x46C6D2U, 0x5F5C89U, 0x144F60U, 0x6FA6F7U, 0x66350EU, 0x2C0A59U, 0x35DAE0U, 0x7EC12FU, 0x0D32FEU, + 0x0429C1U, 0x5FB911U, 0xD642AEU, 0x895167U, 0xC3D8B0U, 0xFAAB89U, 0xB1315AU, 0xA8C0A7U, 0xE3DB24U, 0xB84879U, + 0x913382U, 0xCBA317U, 0x82F8FCU, 0x994BA9U, 0x50C213U, 0x4390CEU, 0x282F5DU, 0x713E30U, 0x7FCDE3U, 0x26565EU, + 0x2D0485U, 0x56BDD4U, 0x1FAE7BU, 0x0475AAU, 0x4DD555U, 0x17CE4CU, 0x9C1D9BU, 0xE52473U, 0xEEF7E4U, 0xB7CD1DU, + 0xF45E42U, 0xEF87E3U, 0x87B43CU, 0x986FADU, 0xD16FD2U, 0x8AD403U, 0x8103A8U, 0xD83A75U, 0x33A826U, 0x2BF39BU, + 0x604049U, 0x7B99A4U, 0x328ABFU, 0x49306AU, 0x407191U, 0x1BEA04U, 0x19D96FU, 0x4001F2U, 0x0FB201U, 0x36E9DCU, + 0xFD7ADFU, 0xE64326U, 0xAF91F9U, 0xF51249U, 0xDC2B16U, 0x87F8D7U, 0xCCE668U, 0xC517B1U, 0x9E8C46U, 0x97BF5FU, + 0xED6498U, 0xA67461U, 0x378FF6U, 0x788C8FU, 0x611514U, 0x0AE6F1U, 0x53FC2BU, 0x596F3EU, 0x0216C5U, 0x4B8508U, + 0x507FBBU, 0x396EE6U, 0x22F535U, 0xE99688U, 0xB10F43U, 0xBA1D36U, 0xC3E2ADU, 0xC07178U, 0x9B28C3U, 0xD69A8BU, + 0xCD817CU, 0x8570E5U, 0xFEEB12U, 0xF5E8CBU, 0xAC10C4U, 0x270335U, 0x7ED8EAU, 0x156B5BU, 0x0E7A14U, 0x46A0C5U, + 0x5D937AU, 0x144AA3U, 0x4F79D5U, 0x6CF35CU, 0x31228FU, 0x7A1932U, 0x628E69U, 0xA9D59CU, 0x926517U, 0xDBBEE2U, + 0x80ADB9U, 0x891424U, 0xD246D7U, 0xD8ED1AU, 0xA17C28U, 0xEA27F5U, 0xF3942EU, 0xB8CE8FU, 0xAB5FD0U, 0x466461U, + 0x1CB7BEU, 0x152F6FU, 0x4E1CC0U, 0x05D799U, 0x1CE66EU, 0x773DF7U, 0x7EAB00U, 0x249048U, 0x6D41D7U, 0x765A26U, + 0x1DA9F9U, 0x8431C8U, 0xCF0203U, 0x96C1DEU, 0x90D86DU, 0xCB6A30U, 0xA23193U, 0xB9A24EU, 0xF05B95U, 0xEB48A0U, + 0xA0D27AU, 0xD8A39FU, 0xD33804U, 0x0A9B79U, 0x01C3AAU, 0x5A5437U, 0x132FD4U, 0x28BC0DU, 0x60253AU, 0x3F57E3U, + 0x3CCC7CU, 0x65DD9DU, 0x4E26C2U, 0x172572U, 0xDCDDADU, 0xC64E64U, 0x8F5553U, 0x94A68AU, 0xFDBE7DU, 0xA66DE4U, + 0xADD68BU, 0xF4C75AU, 0xFE0CC1U, 0x873E34U, 0xC8A72FU, 0xDBD0C2U, 0x124B10U, 0x49998DU, 0x40A8FEU, 0x3A3323U, + 0x316088U, 0x68D95DU, 0x235B06U, 0x3A00B3U, 0x51B178U, 0x4AEA89U, 0x025816U, 0x59C36FU, 0xD092B8U, 0x8B2930U, + 0xE43AC7U, 0xF5E2DEU, 0xBEC121U, 0xA71AF0U, 0xED8B7FU, 0x94B40EU, 0x9F66D1U, 0xD45D68U, 0xCD8CBFU, 0x8617F6U, + 0x5F2545U, 0x75FC98U, 0x2EFF62U, 0x674467U, 0x7C959CU, 0x318F09U, 0x0A7CD2U, 0x4967AFU, 0x11D62CU, 0x1A8CD1U, + 0x431F02U, 0x48A69DU, 0xB3E5ECU, 0xFA7623U, 0xE10E9AU, 0xA99948U, 0xB20215U, 0xD971A6U, 0x80E86BU, 0x8BDA90U, + 0xD60185U, 0x9D907EU, 0x8FFBFBU, 0xE66920U, 0x7D705DU, 0x3483CEU, 0x6F9833U, 0x646BF1U, 0x1DF3E8U, 0x17E017U, + 0x4E1BC6U, 0x050A79U, 0x1E8038U, 0x5773E7U, 0x2C685EU, 0xA1BD89U, 0xFB86B0U, 0xF01477U, 0xA16D8EU, 0xCAFE19U, + 0xD365C1U, 0x9815AEU, 0x839E3FU, 0xCBCDC4U, 0x907611U, 0xB9E70AU, 0xE2BDE7U, 0x2B0E34U, 0x301789U, 0x7BE4DAU, + 0x477707U, 0x0C2FACU, 0x558C79U, 0x5E9743U, 0x0D4496U, 0x04786DU, 0x7FABE0U, 0x3730B3U, 0x3C014AU, 0xE7DADDU, + 0xEEE834U, 0x956163U, 0xDCB2FAU, 0xC78905U, 0x8D5BD4U, 0xD0427BU, 0xDBF12BU, 0xA22AB4U, 0xA93B4DU, 0xFA819AU, + 0xB3D2B3U, 0x287B64U, 0x40289DU, 0x5BB206U, 0x100153U, 0x495CB8U, 0x42CF2DU, 0x3BF4D6U, 0x70248BU, 0x6ABF19U, + 0x23CCF4U, 0x3C4527U, 0x75761AU, 0x8EACC1U, 0x853F44U, 0xD44EBFU, 0xDED5EEU, 0x87C751U, 0xEC3E80U, 0xF72D6FU, + 0xBEB676U, 0xE557A1U, 0xEC4D59U, 0xB6BECEU, 0x9DA527U, 0x443078U, 0x0BCAE9U, 0x12D916U, 0x594087U, 0x6033E8U, + 0x22A831U, 0x7948A2U, 0x70535FU, 0x2BC01CU, 0x62BBA1U, 0x592A7BU, 0x92308EU, 0x8AC395U, 0xC15A50U, 0x9809ABU, + 0xB3B336U, 0xECB245U, 0xE54998U, 0xBEDA1BU, 0xF681E6U, 0xED35F5U, 0x8E2E0CU, 0x87FDD3U, 0x5CC453U, 0x1556ACU, + 0x0E85FDU, 0x64AC42U, 0x3D7F8BU, 0x36447CU, 0x6FD665U, 0x640FB2U, 0x3B3C4BU, 0x52A7C4U, 0x48F7B5U, 0x014C2EU, + 0x9A9FFBU, 0xD19601U, 0xA0250CU, 0xAB7FFFU, 0xF2C822U, 0xB8D1B1U, 0xA302CCU, 0xEAB907U, 0xD1E9B2U, 0x987269U, + 0xC3411CU, 0xCC8897U, 0x141A42U, 0x3F61B8U, 0x66F2A1U, 0x2DCB56U, 0x3618DFU, 0x778208U, 0x2CB3F1U, 0x0468EEU, + 0x5F7B1FU, 0x5693D0U, 0x0D8041U, 0x461B3EU, 0xFFECE7U, 0xB4FD50U, 0xA94798U, 0xE314CFU, 0xB88D76U, 0xB17EADU, + 0xCA7508U, 0xC3E553U, 0x989EA6U, 0xDB0D3DU, 0xC396E8U, 0xA8E683U, 0x717D1EU, 0x7A0EEDU, 0x219730U, 0x288422U, + 0x736ECFU, 0x1BFF14U, 0x04A4A1U, 0x4F177AU, 0x56092BU, 0x1DD884U, 0x64635DU, 0xEF70EAU, 0xA589B3U, 0xF49B54U, + 0xFF50CDU, 0xA66312U, 0x8DFA62U, 0xD628FDU, 0x9F131CU, 0x8582C3U, 0xCCF9DAU, 0xF36A29U, 0xB8B2F4U, 0x618157U, + 0x6A020AU, 0x335999U, 0x79E864U, 0x4272BFU, 0x03259AU, 0x189C40U, 0x51CFB5U, 0x0A752EU, 0x216463U, 0x79BF90U, + 0x721C0DU, 0xAB47FEU, 0xE4D727U, 0xFDEC28U, 0x963FD9U, 0x8DA646U, 0xC594B7U, 0x9E4FE8U, 0x977E60U, 0xECA597U, + 0xAF264EU, 0xB61C79U, 0xFDCDA0U, 0x65D64FU, 0x2E61DCU, 0x553881U, 0x5CAA72U, 0x0351FBU, 0x0A400CU, 0x51FB55U, + 0x3BB9CAU, 0x22223AU, 0x6993B5U, 0x30C8C4U, 0x3B5B1BU, 0xE02B82U, 0xC1B075U, 0x9B23BCU, 0xD25A8BU, 0xC9C852U, + 0x82A3A9U, 0xBB303CU, 0xF42977U, 0xADDA82U, 0xA64418U, 0xFC55E5U, 0xB5AEE6U, 0x0EBD3BU, 0x4765C8U, 0x4CD655U, + 0x17DD2EU, 0x562EEBU, 0x6C3770U, 0x25A585U, 0x3E5EDEU, 0x754F6FU, 0x2C94A1U, 0x23A758U, 0x5A3F4FU, 0xD07C96U, + 0x8BC761U, 0xC254E8U, 0xD92C97U, 0xB0BF06U, 0xEBE0D9U, 0xE25138U, 0xB8CAA7U, 0xBB98DEU, 0xE22109U, 0x896291U, + 0x10F172U, 0x5BCB2FU, 0x401A94U, 0x0CA141U, 0x77B2BAU, 0x7E6BBFU, 0x255964U, 0x6E82D9U, 0x77130AU, 0x3C3877U, + 0x04EAF4U, 0x4FD129U, 0x9C40DBU, 0x959BC6U, 0xCEAC2DU, 0xE774FCU, 0xBC6763U, 0xF6DC12U, 0xEB8DCDU, 0xA00664U, + 0xF9F4B3U, 0xD2EF4AU, 0x895E5DU, 0x800584U, 0x5A972BU, 0x132EFBU, 0x287D84U, 0x63E615U, 0x7297CEU, 0x391D23U, + 0x608E30U, 0x6AF5CDU, 0x11641EU, 0x5C5E93U, 0x4789E0U, 0x0E903DU, 0x956386U, 0xFEF053U, 0xB6E879U, 0xAD0BACU, + 0xE41077U, 0xFF83CAU, 0xB47A99U, 0xCD6870U, 0xCE93E7U, 0x96823EU, 0x9D1941U, 0xC4EBD0U, 0x2BF23FU, 0x3031EEU, + 0x790A71U, 0x229909U, 0x2AC1CEU, 0x717677U, 0x5AEDA0U, 0x039C99U, 0x480646U, 0x515587U, 0x1AEC3CU, 0x296F69U, + 0xE13492U, 0xBA8607U, 0xB39FCCU, 0xEC4CB1U, 0xA77723U, 0x9EA7DEU, 0xD51C0DU, 0xCD0F00U, 0x86D4FBU, 0xDDF56EU, + 0xF46F95U, 0x2FBCD4U, 0x268D6BU, 0x7D52B2U, 0x374165U, 0x26F9DCU, 0x4D2A9BU, 0x141163U, 0x1FD2FCU, 0x40CA2DU, + 0x497952U, 0x3322D3U, 0x7AB32CU, 0xE108F5U, 0xAA5AE2U, 0xB3E31BU, 0xF8B098U, 0x812B65U, 0x8B8936U, 0xD0D08AU, + 0xD94341U, 0x8A7894U, 0xE3A9AFU, 0xF8377AU, 0xB74481U, 0x6FDD0CU, 0x64EE5FU, 0x3D35A2U, 0x163731U, 0x5F8ECCU, + 0x045DC7U, 0x0F4616U, 0x57B6E8U, 0x7CAD79U, 0x253E86U, 0x6EC7CFU, 0x7DD478U, 0xB426A1U, 0xCF2D76U, 0xC3BC5FU, + 0x984780U, 0x935571U, 0xCACCEEU, 0x81BBBFU, 0xB82054U, 0xF371C0U, 0xE9CB3BU, 0xA05826U, 0xFB33F5U, 0x52A218U, + 0x09B88BU, 0x424BF6U, 0x53D22DU, 0x198198U, 0x043A53U, 0x6F2A06U, 0x34F1BDU, 0x3DC260U, 0x664982U, 0x6FB81BU, + 0x15A24CU, 0xDE71F5U, 0xC7482AU, 0x8CDFCBU, 0x9505D4U, 0xDE3405U, 0xA5EFFAU, 0xA4FC63U, 0xFE5704U, 0xB387DDU, + 0xA8BC6AU, 0xC32FB2U, 0x5A7EE5U, 0x11C44CU, 0x489797U, 0x420E62U, 0x19BD79U, 0x30E6BCU, 0x6B6407U, 0x225DDAU, + 0x398EA9U, 0x703534U, 0x0A64F7U, 0x09FA0AU, 0xD4C910U, 0xDF10E5U, 0x86833EU, 0xCDB99BU, 0xE67A40U, 0xBE631BU, + 0xB590AEU, 0xEC8B75U, 0xA73BD0U, 0x9CE08BU, 0xD5F35EU, 0x8E0AE5U, 0x061828U, 0x5D835AU, 0x5660C7U, 0x277914U, + 0x68CAE9U, 0x7190E2U, 0x3A0113U, 0x20FECCU, 0x49ED7DU, 0x127522U, 0x1B06ABU, 0x40855CU, 0x8B9E85U, 0x926FB2U, + 0xF8F56AU, 0xE186A5U, 0xAA1F14U, 0xF10CCBU, 0xF0F7BAU, 0x8F6735U, 0x867CECU, 0xDC9F1FU, 0x978402U, 0x8E54F1U, + 0x45EF3CU, 0x7CFC8FU, 0x3705D2U, 0x6C1248U, 0x64C8BDU, 0x3FF976U, 0x566243U, 0x4DA198U, 0x069B45U, 0x1F0AF6U, + 0x5851BBU, 0x00E248U, 0xAB3BD1U, 0xF2090EU, 0xF9926FU, 0xA2C3F1U, 0xEB7800U, 0xD07B9FU, 0x98A1E6U, 0xC31021U, + 0xC84BB8U, 0x91D84FU, 0x9AEC96U, 0x6337A9U, 0x288468U, 0x369FB3U, 0x774E06U, 0x6C645DU, 0x05B7A9U, 0x4E2E22U, + 0x551DFFU, 0x1CC78CU, 0x47D611U, 0x4F2DF2U, 0x343E6FU, 0xBF8514U, 0xE655C1U, 0xAD5E5AU, 0xB4EDBFU, 0xDFB4E4U, + 0xC1265DU, 0x80DD8BU, 0xDBC852U, 0xD25375U, 0x8920ACU, 0xA2BA53U, 0xFB0BC2U, 0x31401DU, 0x28D33CU, 0x63AAE3U, + 0x18381AU, 0x11238DU, 0x4AD2E4U, 0x434933U, 0x195BABU, 0x56A058U, 0x6FB105U, 0x2C5AAEU, 0x35C97BU, 0xFED9A0U, + 0xA52295U, 0x8D314EU, 0xD6ECA3U, 0x9F5E30U, 0x84456DU, 0xCFB6DEU, 0xD6AF03U, 0xBD2CE9U, 0xE556FCU, 0xEEC707U, + 0xB71CD6U, 0x382F59U, 0x43B720U, 0x02E4F7U, 0x195F4EU, 0x51CC99U, 0x0AA550U, 0x013767U, 0x786CBEU, 0x73DD01U, + 0x2AC6D1U, 0x61159EU, 0x7BA92FU, 0x92BAF4U, 0x896109U, 0xC0521AU, 0x9F9AF7U, 0x942924U, 0xC532B9U, 0xEFE3C2U, + 0xA6D807U, 0xFD0ABCU, 0xF69369U, 0xAFA033U, 0x44738EU, 0x5D694DU, 0x17C8F0U, 0x0C93A3U, 0x45207AU, 0x1EF9C5U, + 0x37EB04U, 0x6850FBU, 0x6305EAU, 0x3B9E15U, 0x782DC4U, 0x41774BU, 0x8AF633U, 0xD18DE4U, 0xD81E5DU, 0x83A69AU, + 0x8AF583U, 0xF06E7CU, 0xBB5FADU, 0xA28416U, 0xE99653U, 0xF06D88U, 0x9FEC35U, 0xC4F7E6U, 0x4C059AU, 0x1F1C19U, + 0x56EFC4U, 0x4D743FU, 0x24612AU, 0x3F9BD1U, 0x748814U, 0x2C13AFU, 0x27F276U, 0x5EE861U, 0x553B88U, 0x0E0A5FU, + 0xC791E6U, 0xD8E2B0U, 0x907A69U, 0xABE9C6U, 0xE09217U, 0xB10168U, 0xBA48F9U, 0xE3FA26U, 0x8861CFU, 0x9230D8U, + 0xDB8B21U, 0xC099B2U, 0x09644FU, 0x52F704U, 0x79AC90U, 0x201F6BU, 0x2E17BEU, 0x77C495U, 0x3CFF48U, 0x172E9BU, + 0x4E9426U, 0x0D8775U, 0x145E98U, 0x5E6D03U, 0xC5F6D6U, 0xAC242DU, 0xF70D3CU, 0xFEDED2U, 0xA5C543U, 0xAE74BCU, + 0xD62EE5U, 0x9D9D72U, 0x80029BU, 0xCB534CU, 0x90E175U, 0x19BAAAU, 0x6A3B6BU, 0x6280D4U, 0x39D385U, 0x724B7AU, + 0x6B78E2U, 0x00A321U, 0x19101CU, 0x5248CFU, 0x0ADB30U, 0x01F0A9U, 0x5A21CEU, 0xB73A17U, 0xACC880U, 0xE55179U, + 0xFE42A6U, 0xB4B987U, 0xC5AF58U, 0xCE1688U, 0x97C533U, 0x9CCE76U, 0xC73F8DU, 0x8E2510U, 0xB4B6C3U, 0x7D4FFEU, + 0x665C3DU, 0x2DC7C0U, 0x70B55BU, 0x5B2C2EU, 0x025FF5U, 0x49D470U, 0x53448AU, 0x1A3FD7U, 0x09AC64U, 0x60BDBDU, + 0x3B467AU, 0xB0D043U, 0xE98B9CU, 0xE33A2DU, 0x9A21E2U, 0xD1C3B3U, 0xCA5A0CU, 0x8709DDU, 0xDCB222U, 0xF5A3AAU, + 0xBF79DDU, 0xA44A04U, 0xEDD193U, 0x3E006AU, 0x373B21U, 0x4CF994U, 0x47C04FU, 0x1F53DAU, 0x5488A1U, 0x4DB86CU, + 0x2623DFU, 0x7D7402U, 0x70CF50U, 0x2B9EFDU, 0x232426U, 0xF8A7D3U, 0x91FEC8U, 0x8A4D39U, 0xC117F6U, 0xD0866FU, + 0x9B3D18U, 0xE36EC1U, 0xE8F576U, 0xB3C5BFU, 0xBA1629U, 0xE1BD50U, 0xA8EC8FU, 0x17763EU, 0x5D45F1U, 0x049CA0U, + 0x0F8F1FU, 0x5630C6U, 0x7DE225U, 0x26FB38U, 0x6F08CBU, 0x7D0316U, 0x34B28DU, 0x2F68E9U, 0xC47B72U, 0x9DC287U, + 0x96915CU, 0xCF0B41U, 0x85F8A2U, 0xBAE17FU, 0xF372CCU, 0xE81991U, 0xA1894AU, 0xFAF2EBU, 0xF16134U, 0x89F845U, + 0x0A8ADBU, 0x53153AU, 0x1806E5U, 0x03FF7CU, 0x6A7C0BU, 0x312692U, 0x399775U, 0x628CACU, 0x6D7FB3U, 0x34EE42U, + 0x5FF49DU, 0x56073CU, 0x8D1C67U, 0x87CDBBU, 0xDEE708U, 0xB574D5U, 0xA4ADB6U, 0xEF9E2BU, 0xF605D0U, 0xBD7545U, + 0xE6EE0EU, 0xCE39FBU, 0x950260U, 0xD8929DU, 0x43D9CEU, 0x086A47U, 0x31B3B1U, 0x7AA068U, 0x221ADFU, 0x294B86U, + 0x72F049U, 0x73E3F8U, 0x083927U, 0x418856U, 0x5AC3C9U, 0x105020U, 0xC969B7U, 0xE2BBEEU, 0xBF2019U, 0xB41181U, + 0xEFCA6AU, 0xA6FD3FU, 0xBC27A4U, 0xD53651U, 0xCE9D9AU, 0x854EA7U, 0xDC5E74U, 0xDFE5A9U, 0x26B61AU, 0x6C0D57U, + 0x77DCECU, 0x3EC639U, 0x2575C3U, 0x682CD6U, 0x13AF1DU, 0x1855ECU, 0x404473U, 0x4BDF8AU, 0x12ACDDU, 0xF93754U, + 0xE207A3U, 0xABD87AU, 0xF04B45U, 0xF03284U, 0xABB05BU, 0x80ABEBU, 0xD95AB4U, 0x92C10DU, 0x8FD2CEU, 0xC42833U, + 0xEC3920U, 0x37C2FDU, 0x7C5106U, 0x654883U, 0x2EAAF8U, 0x37B12DU, 0x5C20B6U, 0x065B42U, 0x07C909U, 0x5C12B4U, + 0x152367U, 0x2EB4FAU, 0x65CF19U, 0xFC5F40U, 0xB294FFU, 0xEBA72EU, 0xE03ED1U, 0x9B6CD0U, 0x92D70FU, 0xC944F6U, + 0x801D60U, 0x9AAE19U, 0xF1F4DEU, 0xA85547U, 0xAB4EB8U, 0x729DE9U, 0x792456U, 0x223697U, 0x4BED0CU, 0x55DE71U, + 0x1C03A2U, 0x07910FU, 0x4CAADCU, 0x356BA0U, 0x3E5033U, 0x67C3EEU, 0x2D9B05U, 0xB62810U, 0xFFF3EBU, 0xC4E03EU, + 0x8558A5U, 0xDE0B48U, 0xD5905BU, 0x8D71A2U, 0xA26A75U, 0xFBD8ECU, 0xB08982U, 0xAB1253U, 0xE2A1ECU, 0x79FB3FU, + 0x116E52U, 0x4A15C9U, 0x43861CU, 0x188FE7U, 0x537DF2U, 0x62E619U, 0x29D7C0U, 0x310C57U, 0x7A1F2EU, 0x25E5B8U, + 0xAC7451U, 0xC76F86U, 0xDE9C9FU, 0x959460U, 0xCF27B1U, 0xC6FC1EU, 0xBDEDCFU, 0xF416B0U, 0xEF0429U, 0xA49FEEU, + 0xBDEA17U, 0xFF7104U, 0x06A3F8U, 0x0D8A63U, 0x5219A6U, 0x5B62DDU, 0x00F348U, 0x6969B3U, 0x731A6EU, 0x38816DU, + 0x61D090U, 0x6A6343U, 0x33F9FEU, 0x18B8A5U, 0xC30340U, 0x8B10DAU, 0x98E80BU, 0xD1FB74U, 0xEA20F5U, 0xA5930AU, + 0xFC8E93U, 0xF75CC4U, 0xAF673DU, 0xA4E6BAU, 0xDF3D43U, 0x960F9CU, 0x0DD68DU, 0x44E572U, 0x1F7EB2U, 0x35AD09U, + 0x6C9554U, 0x6746A7U, 0x365D3AU, 0x7DFCF9U, 0x64A6C4U, 0x0B351FU, 0x118CEAU, 0x58DF61U, 0x836434U, 0x8A36CFU, + 0xF1AB5BU, 0xBA18A0U, 0xA343EDU, 0xE8C27EU, 0xF0F887U, 0xBB2B50U, 0xC03A69U, 0xC9C1A6U, 0x9A5317U, 0x9368C8U, + 0x5CB919U, 0x26A226U, 0x2F01EFU, 0x74D919U, 0x3DCA80U, 0x2631D7U, 0x6D223EU, 0x54BAA1U, 0x1E4950U, 0x47520BU, + 0x4CA79EU, 0x97BC75U, 0xBE3EA8U, 0xED479BU, 0xA4D446U, 0xBA4FF5U, 0xF13C39U, 0xE8A46AU, 0x83D7D7U, 0xDA4C0CU, + 0xD1DDF9U, 0x8AA7F2U, 0xC22427U, 0x793DDCU, 0x30CE45U, 0x2B5522U, 0x6007FBU, 0x39BE6CU, 0x32AD95U, 0x42560BU, + 0x4D426AU, 0x16D1B5U, 0x5F3A04U, 0x442BDBU, 0x2DF082U, 0xF6C225U, 0xFE59FCU, 0xA5880FU, 0xAEB312U, 0xF761C9U, + 0x9C582CU, 0x85CBB7U, 0xCE00C3U, 0xD43118U, 0x9DAB9DU, 0xEAF866U, 0xE3437BU, 0x381288U, 0x738955U, 0x6A3BF6U, + 0x2066ABU, 0x19D570U, 0x52DEC1U, 0x090E1EU, 0x00B5FFU, 0x5BE6E1U, 0x727D38U, 0x284CCFU, 0x639656U, 0xFA8531U, + 0xBD3CA8U, 0xD4EF77U, 0xCFC586U, 0x841489U, 0x9C0F78U, 0xD7BCA7U, 0x8E671EU, 0xA5774DU, 0xFE8481U, 0xF79F32U, + 0xAC0AEFU, 0x65F09CU, 0x5FF301U, 0x144ACAU, 0x0D193FU, 0x468224U, 0x13F0D1U, 0x18694AU, 0x63FA87U, 0x2B81F4U, + 0x30106DU, 0x790A9BU, 0xE2E952U, 0x8970CDU, 0xD003BCU, 0xDB9963U, 0x838AD2U, 0x88731DU, 0xD1E064U, 0xBAFFF3U, + 0xA10F2AU, 0xEC049DU, 0xBFD7D4U, 0xB7EE2BU, 0x4C7CBBU, 0x478760U, 0x1E9415U, 0x554D9EU, 0x4C7E6BU, 0x07E4B0U, + 0x3D35ADU, 0x741E4EU, 0x2F8D93U, 0x26FC20U, 0x7D667DU, 0x16B586U, 0x8B8E02U, 0xC91FD9U, 0xD0456CU, 0x9BF237U, + 0xC0EBCEU, 0xE92849U, 0xB29390U, 0xBBC3E7U, 0xE1787EU, 0xAA6B81U, 0x93B040U, 0xD8005FU, 0x411BAEU, 0x0AC870U, + 0x51F1D1U, 0x5D328EU, 0x362837U, 0x6799E0U, 0x6C4239U, 0x37711AU, 0x3EABC7U, 0x45BA3CU, 0x0D01A9U, 0x16D6F2U, + 0xDDCF17U, 0xC46D8CU, 0x8F3670U, 0xF6A723U, 0xFD5CBCU, 0xA74F5DU, 0xEAF582U, 0xF1A43BU, 0x903768U, 0x8B0CC5U, + 0xC0DC16U, 0x9957CBU, 0x1324F0U, 0x4ABD25U, 0x61AECEU, 0x38545AU, 0x73C701U, 0x68FEF4U, 0x212D6FU, 0x5B3382U, + 0x52C2D1U, 0x09494CU, 0x065ABFU, 0xDFA126U, 0x9CB149U, 0xA56A98U, 0xEE5927U, 0xF4C0F6U, 0xBD33B8U, 0xE62901U, + 0xCFB8D6U, 0x94D32FU, 0x9F40B8U, 0xC69AF1U, 0x8CAB0EU, 0x15309FU, 0x7E6360U, 0x21DA31U, 0x2848BAU, 0x733747U, + 0x72A6D4U, 0x08EDA8U, 0x435F7BU, 0x5A4CD6U, 0x119505U, 0x082658U, 0x433DE3U, 0xB8ED26U, 0xB0D6DDU, 0xEB05C8U, + 0xA2BC13U, 0xA9BEEAU, 0xD6656DU, 0xDF5614U, 0x848F82U, 0xC41C5BU, 0xDF26A4U, 0x94F7A5U, 0xADCC5AU, 0x665B8BU, + 0x3F1234U, 0x34A0EDU, 0x6E7BAAU, 0x076813U, 0x1CD1C4U, 0x55833DU, 0x4E1836U, 0x03A9E2U, 0x58F219U, 0x72418CU, + 0x2B09F7U, 0xA89A72U, 0xF1A1A9U, 0xBA7254U, 0x81EA47U, 0xC899BAU, 0xD20279U, 0x9B13C4U, 0xC0E09FU, 0xCB7E4BU, + 0xB25FF0U, 0xF98431U, 0xE4974EU, 0x2E6CD7U, 0x35FC00U, 0x5CE7A9U, 0x07147EU, 0x060D07U, 0x5D9F98U, 0x56E449U, + 0x0E65A6U, 0x659EB7U, 0x7C8D49U, 0x371790U, 0x6C6623U, 0xE5FD6EU, 0x9E6EBDU, 0x921600U, 0xC985D3U, 0x82DAEEU, + 0x9B7B25U, 0xD0E0F0U, 0xE1924BU, 0xAA091EU, 0xF158F5U, 0xF9E369U, 0x22F1BAU, 0x4B28C7U, 0x509B54U, 0x1B80BDU, + 0x024162U, 0x497B53U, 0x01A88CU, 0x3E1B5DU, 0x7502F2U, 0x6CD12BU, 0x27EB1CU, 0x7E7AC5U, 0xDDA113U, 0x8596BAU, + 0xCE5EEDU, 0xD54D14U, 0x9CF68BU, 0x87A54AU, 0xEE1C31U, 0xB58EA4U, 0xBFD55FU, 0xE66482U, 0xE93FA1U, 0x90AD7CU, + 0x5B04EFU, 0x405713U, 0x09CC48U, 0x13BFEDU, 0x522736U, 0x2914E3U, 0x22CFD8U, 0x7B5E05U, 0x3061E6U, 0x29B37FU, + 0x43BAA8U, 0x5849D1U, 0x91D25EU, 0xCEE0AFU, 0xC73971U, 0x9C2A40U, 0xB7919FU, 0xEF401EU, 0xA452E1U, 0xB5B9B8U, + 0xFEA80FU, 0x8533D6U, 0x8C4115U, 0xD7DA28U, 0x5F6BF3U, 0x043006U, 0x4FA39DU, 0x76DBD9U, 0x394C22U, 0x20C7BFU, + 0x6BB64CU, 0x312C41U, 0x187FB2U, 0x43C46FU, 0x0A55F4U, 0x192E81U, 0xD2BC4AU, 0xCBA5FBU, 0xA15624U, 0xF85DFDU, + 0xF38ECBU, 0xBA3602U, 0xA125F5U, 0xCEFE6CU, 0x97CF3BU, 0x9D55C2U, 0xC4A64DU, 0x4FBFBCU, 0x1468A3U, 0x7D4352U, + 0x6ED19DU, 0x270804U, 0x7D3B76U, 0x76A0ABU, 0x0FF018U, 0x0443D5U, 0x5D188EU, 0x16A93BU, 0x0932E0U, 0xC07015U, + 0xFACB1EU, 0xB39AC3U, 0xE80170U, 0xE3B3ADU, 0xBAEA5EU, 0xD17956U, 0xC042A9U, 0x8A9378U, 0x912DE7U, 0xD86E86U, + 0x83F559U, 0x2AC4E8U, 0x711F37U, 0x7A0D6EU, 0x26B4C9U, 0x6D6710U, 0x547CE7U, 0x1F8CFEU, 0x449720U, 0x4D3483U, + 0x16EF5AU, 0x1EFE2DU, 0x6D44B4U, 0xA6174BU, 0xBF8E8AU, 0xF4FD95U, 0xED6764U, 0x86D6BBU, 0xDC8912U, 0xD10A45U, + 0x8A799CU, 0x83E12AU, 0xF872F3U, 0xB10954U, 0xAA980DU, 0x6083D6U, 0x397163U, 0x3AE8B8U, 0x439BDDU, 0x481046U, + 0x1302BBU, 0x5AFB68U, 0x50E875U, 0x297396U, 0x26824AU, 0x7D98F1U, 0x344BA4U, 0xAF726FU, 0xE6F5DAU, 0x9C0F01U, + 0x971C38U, 0xCE85EFU, 0xC5F626U, 0x946D91U, 0xFFBDC8U, 0xE48637U, 0xAC15A6U, 0xB74C48U, 0x7EEE99U, 0x21B586U, + 0x0A0677U, 0x539FA8U, 0x18CC01U, 0x007652U, 0x4B67CFU, 0x70B43CU, 0x390FF1U, 0x625ECAU, 0x6BD01FU, 0x38E3C4U, + 0xB23870U, 0xCB893BU, 0x8093C6U, 0x994055U, 0xD679A8U, 0x8DAAFBU, 0xA4B176U, 0xFE018DU, 0xF7CA5CU, 0xACD963U, + 0xE762B2U, 0xFE323DU, 0x1589C4U, 0x0C5A92U, 0x4F432BU, 0x17F0ECU, 0x1CAA35U, 0x673B82U, 0x6E54DBU, 0x31C724U, + 0x785CA5U, 0x632C5AU, 0x29B70BU, 0x508490U, 0xDB5D6DU, 0x82CFEEU, 0x89B492U, 0xD22541U, 0xBB2EDCU, 0xA1DD27U, + 0xE04F62U, 0xFB56D9U, 0xB0A50CU, 0xF9BED7U, 0xC24EFAU, 0x8F5529U, 0x55C6D0U, 0x5E3B47U, 0x07383FU, 0x2CA2F0U, + 0x75D161U, 0x3E489EU, 0x25BB0FU, 0x6DA170U, 0x7630B1U, 0x174B2EU, 0x4CD8D7U, 0x470180U, 0x9E2339U, 0xD5B8FEU, + 0xE9EB27U, 0xA2521DU, 0xB941C8U, 0xF0BB23U, 0xAB2AB6U, 0xA271CDU, 0xD9C250U, 0xD3DC83U, 0x8A1D6EU, 0x41A67DU, + 0x58B580U, 0x3B6C5BU, 0x205ECEU, 0x6985A5U, 0x333471U, 0x3E27CAU, 0x65FD13U, 0x0CCE44U, 0x1747EDU, 0x5C143AU, + 0x45AF83U, 0x8F7F54U, 0xF6643DU, 0xFDD7A2U, 0xA68E73U, 0xAF3D8CU, 0xF4E79DU, 0xB5E073U, 0x8F59AAU, 0xC40A3DU, + 0x999044U, 0x922197U, 0xCB7A3AU, 0x60E9E1U, 0x3B90B4U, 0x73020FU, 0x6839DAU, 0x21FA71U, 0x3A632CU, 0x5151DFU, + 0x088A43U, 0x039B80U, 0x4260FDU, 0x18F36EU, 0x33EB97U, 0xEE1848U, 0xE503C9U, 0xBCA4B6U, 0xF7FC67U, 0xEC6FD8U, + 0x849C01U, 0x9F8506U, 0xD616FFU, 0x8D6C29U, 0x86FD90U, 0xFF26CFU, 0xF4150EU, 0x2C9EB1U, 0x6FEE60U, 0x74751BU, + 0x39E696U, 0x429F65U, 0x4B0DB8U, 0x1056ABU, 0x1AE756U, 0x43FC9DU, 0x282F29U, 0x318172U, 0x7A90E7U, 0xE36B1CU, + 0xA878D9U, 0xF2A0E2U, 0xDB133FU, 0x8008ECU, 0xC1D955U, 0xDAE292U, 0x9570EBU, 0xAC9B74U, 0xE68A85U, 0xBF514BU, + 0x34635AU, 0x6FFAA5U, 0x66A93CU, 0x1D12CBU, 0x54C382U, 0x4ED915U, 0x056AECU, 0x5C2D37U, 0x779402U, 0x2607C9U, + 0x2D5D1CU, 0x72ECA6U, 0xBAB7FBU, 0xA12408U, 0xC89C85U, 0xD3CF76U, 0x98542BU, 0xC177B8U, 0xCAAE45U, 0xB29CCEU, + 0xB9473BU, 0xE2D660U, 0xABEDF1U, 0xA03F1EU, 0x7926C4U, 0x1A95F1U, 0x044E2AU, 0x4D49FFU, 0x56B154U, 0x1FA209U, + 0x6419FAU, 0x6F4867U, 0x36D394U, 0x3C2199U, 0x653842U, 0x2EABB7U, 0x95C02CU, 0xDC525CU, 0x87CB93U, 0x8EB80AU, + 0xD423FDU, 0xF152A4U, 0xAAC003U, 0xE15BDAU, 0xF82A0DU, 0xB3B134U, 0xAAB3EBU, 0xC14C0AU, 0x1B5D95U, 0x128664U, + 0x49357AU, 0x002DA3U, 0x3BDE40U, 0x70C5DDU, 0x6954AEU, 0x23AE73U, 0x76ADE8U, 0x7D760DU, 0x064756U, 0x0FDCE3U, + 0xD40E38U, 0x9D37F5U, 0x87E4C6U, 0xECDF1AU, 0xB54EA9U, 0xBE1470U, 0xE7B71FU, 0xEC288EU, 0xB77951U, 0xDFC3A0U, + 0xC490BFU, 0x89095EU, 0x1ABA81U, 0x51E118U, 0x2853EFU, 0x234AB6U, 0x7B8910U, 0x703AC9U, 0x2B6216U, 0x62F127U, + 0x59CAECU, 0x101B59U, 0x4B2082U, 0xC1F2FFU, 0x88696CU, 0xB358A1U, 0xFA9752U, 0xAD844FU, 0xA63CB4U, 0xFFEF60U, + 0xF5F4EBU, 0x8C059EU, 0xC71F45U, 0xDCACF0U, 0x95772BU, 0x4E6622U, 0x67CDD5U, 0x3D9F0CU, 0x3406BBU, 0x6F75F2U, + 0x24EE0DU, 0x3D7E9CU, 0x520542U, 0x4396B3U, 0x09ADBCU, 0x527C45U, 0x5BF292U, 0xA0810BU, 0xE91878U, 0xF20BB5U, + 0xB9F10EU, 0xA1E0DBU, 0xEA33C0U, 0x938835U, 0x989BFEU, 0xC36342U, 0xCA6011U, 0x95FBECU, 0xFD0A6FU, 0x6E11B2U, + 0x25C3C1U, 0x3CFA5CU, 0x7769A7U, 0x0EB266U, 0x058079U, 0x5E1988U, 0x167E17U, 0x0DE5EFU, 0x44B428U, 0x7F0E31U, + 0x349DC6U, 0xEDC41FU, 0xE277A0U, 0xBA6DE1U, 0x99BE1EU, 0xC2178FU, 0x8B4450U, 0x90FF39U, 0xD9EFAAU, 0x823457U, + 0xA88785U, 0xF1DE98U, 0xFA4D73U, 0x3377E6U, 0x68A41DU, 0x43AD48U, 0x1A1AD3U, 0x14C836U, 0x4DF1EDU, 0x0622D0U, + 0x173903U, 0x7C88FEU, 0x27527DU, 0x2E41A5U, 0xF4FADAU, 0xFDBB4BU, 0x8601A4U, 0xCDD235U, 0xD4CB6AU, 0x9F7893U, + 0x862304U, 0xCCB3EDU, 0xB388BAU, 0xBA5B23U, 0xE1C0DCU, 0xE8A00DU, 0x3B3F27U, 0x500CF2U, 0x48D509U, 0x034694U, + 0x5A3CC7U, 0x51AD6AU, 0x0AB6B9U, 0x234544U, 0x785E57U, 0x30DE9AU, 0x2B2561U, 0x6036F4U, 0xDDCF8FU, 0x96DD5BU, + 0xCF46D0U, 0xCCB729U, 0x96A4FEU, 0xDF3FC7U, 0xE44D10U, 0xADC4F9U, 0xB61366U, 0xFD2837U, 0xA4B888U, 0x8EC359U, + 0x5750B6U, 0x5C49AFU, 0x07BA79U, 0x4A2080U, 0x517307U, 0x38DA7EU, 0x62C9ADU, 0x611230U, 0x38A2CBU, 0x33F98EU, + 0x4A4A35U, 0x0153E0U, 0x98815BU, 0xD23A06U, 0xD929C5U, 0x80E079U, 0xEBD7AAU, 0xF20D57U, 0xBD1C4CU, 0xE6A78DU, + 0xEF7472U, 0x954CE3U, 0x9CDF9CU, 0xCF8455U, 0x0437C2U, 0x1DFE3BU, 0x56EC6CU, 0x6F57D5U, 0x25061BU, 0x7E95AAU, + 0x772FF5U, 0x2C7C24U, 0x05C59BU, 0x5A965AU, 0x111D21U, 0x892DBCU, 0xC2F26FU, 0x9B6192U, 0xB81891U, 0xE38B6EU, + 0xEA91B6U, 0xB16221U, 0xF9FB48U, 0xC2C8DFU, 0x890226U, 0x9013F9U, 0xDBE848U, 0x02FB07U, 0x0D62D6U, 0x77906DU, + 0x3E8BB0U, 0x2538C3U, 0x6C614EU, 0x77F39CU, 0x141861U, 0x4D0D7AU, 0x47968FU, 0x1EE544U, 0x157DD1U, 0xCEEEAAU, + 0xA7953FU, 0xBC06D4U, 0xF57E09U, 0xABED3AU, 0xA2EEE3U, 0xD91734U, 0xD2849CU, 0x8BDEC3U, 0xC06F32U, 0xD174ADU, + 0x9BA77CU, 0x201C93U, 0x690C8AU, 0x22F77DU, 0x3BF4E4U, 0x702933U, 0x4B9B5AU, 0x0380C1U, 0x585134U, 0x556AEEU, + 0x0EF9CBU, 0x45A310U, 0x7C12CDU, 0xB7C97EU, 0xAFEA23U, 0xEC72C0U, 0xB7215DU, 0x9E9A8EU, 0xC50BF3U, 0xCC5068U, + 0x97E28DU, 0xDDB916U, 0xC42846U, 0xAF93B9U, 0xF2D020U, 0x796CC7U, 0x223F9EU, 0x2BA429U, 0x5095F0U, 0x18473FU, + 0x03DC8EU, 0x40EFD1U, 0x593620U, 0x1225BFU, 0x6BCF76U, 0x605E40U, 0xBA6599U, 0xF3B66AU, 0xE8AEF7U, 0x851DBCU, + 0x9EC649U, 0xD5D5D2U, 0x8C2C27U, 0x863E7CU, 0xDFB5D9U, 0xF4C002U, 0xA55BDFU, 0xEEE9ECU, 0x75B020U, 0x3C23D3U, + 0x06584AU, 0x4FCB15U, 0x1453A4U, 0x1F306BU, 0x42AB9AU, 0x09FA05U, 0x30415CU, 0x7A53ABU, 0x61AA22U, 0x2839D5U, + 0xF3228CU, 0xDAD032U, 0x89C9E3U, 0x820A2CU, 0xCAB91DU, 0x91A4C6U, 0x985673U, 0xE34DB8U, 0xA8DCE5U, 0xB52756U, + 0xFE358BU, 0xE6EE78U, 0x0DDF75U, 0x5654AFU, 0x5F075AU, 0x04BFC1U, 0x0D2CB4U, 0x56577FU, 0x34C6C2U, 0x2D9D11U, + 0x662F48U, 0x3FB4FFU, 0x34E536U, 0x4F4E89U, 0xC61C58U, 0x988107U, 0xD132A7U, 0xCA6978U, 0x81D881U, 0xB8C296U, + 0xF3114FU, 0xAA2AA8U, 0xA0FB31U, 0xF37142U, 0xDA429FU, 0x819B24U, 0x4888E1U, 0x5333FAU, 0x1AE30FU, 0x40D0D5U, + 0x6F0B68U, 0x36182BU, 0x3DA0F6U, 0x646345U, 0x2F7898U, 0x14CDF3U, 0x5C9666U, 0xC704BDU, 0x8E7F4CU, 0xDDEED3U, + 0xD655BAU, 0xAF062DU, 0xE49EF5U, 0xFDFD02U, 0xB7661BU, 0xA8F7F4U, 0xC18D25U, 0x9A1E9AU, 0x9305CBU, 0x48F414U, + 0x43EFB5U, 0x1B1D6AU, 0x708413U, 0x698780U, 0x2A7C4DU, 0x6168BFU, 0x78F3A2U, 0x130059U, 0x0B1BCCU, 0x40CA07U, + 0x1FF072U, 0x9663E9U, 0xCD9A14U, 0xE499C7U, 0xBF0AEAU, 0xF57239U, 0xECE1E4U, 0xA7BA5FU, 0xDE098FU, 0xD591E0U, + 0x86E271U, 0x8F79AEU, 0xD52817U, 0x1C8350U, 0x2711A9U, 0x684C3EU, 0x71FFE7U, 0x3AE490U, 0x633619U, 0x498FE6U, + 0x10DC37U, 0x1B670DU, 0x4066D8U, 0x09BC13U, 0x328FAEU, 0xFB16FDU, 0xA9C500U, 0xA2FF93U, 0xFB2C5EU, 0xF03565U, + 0x8D86B0U, 0xC65D4BU, 0xDD7DCEU, 0x95E615U, 0x8EB169U, 0xE708FAU, 0xBCDB03U, 0x37C1C4U, 0x6E72FDU, 0x25232AU, + 0x3DB8F3U, 0x5ECA4CU, 0x45430DU, 0x0CF0B2U, 0x57AB61U, 0x5E3ABCU, 0x210087U, 0x2BD343U, 0xF248B8U, 0xB9392DU, + 0xA0A376U, 0xEBB09FU, 0x905908U, 0x99CAF1U, 0xD3F5A6U, 0xCA251FU, 0x813ED0U, 0xF2CD01U, 0xFBD63EU, 0xA046EEU, + 0x29BD51U, 0x76AE98U, 0x3C274FU, 0x055476U, 0x4ECEA5U, 0x573F58U, 0x1C24DBU, 0x47B786U, 0x6ECC7DU, 0x345CE8U, + 0x7D0703U, 0x66B456U, 0xAF3DECU, 0xBC6F31U, 0xD7D0A2U, 0x8EC1CFU, 0x80321CU, 0xD9A9A1U, 0xD2FB7AU, 0xA9422BU, + 0xE05184U, 0xFB8A55U, 0xB22AAAU, 0xE831B3U, 0x63E264U, 0x1ADB8CU, 0x11081BU, 0x4832E2U, 0x0BA1BDU, 0x10781CU, + 0x784BC3U, 0x679052U, 0x2E902DU, 0x752BFCU, 0x7EFC57U, 0x27C58AU, 0xCC57D9U, 0xD40C64U, 0x9FBFB6U, 0x84665BU, + 0xCD7540U, 0xB6CF95U, 0xBF8E6EU, 0xE415FBU, 0xE62690U, 0xBFFE0DU, 0xF04DFEU, 0xC91623U, 0x028520U, 0x19BCD9U, + 0x506E06U, 0x0AEDB6U, 0x23D4E9U, 0x780728U, 0x331997U, 0x3AE84EU, 0x6173B9U, 0x6840A0U, 0x129B67U, 0x598B9EU, + 0xC87009U, 0x877370U, 0x9EEAEBU, 0xF5190EU, 0xAC03D4U, 0xA690C1U, 0xFDE93AU, 0xB47AF7U, 0xAF8044U, 0xC69119U, + 0xDD0ACAU, 0x166977U, 0x4EF0BCU, 0x45E2C9U, 0x3C1D52U, 0x3F8E87U, 0x64D73CU, 0x296574U, 0x327E83U, 0x7A8F1AU, + 0x0114EDU, 0x0A1734U, 0x53EF3BU, 0xD8FCCAU, 0x812715U, 0xEA94A4U, 0xF185EBU, 0xB95F3AU, 0xA26C85U, 0xEBB55CU, + 0xB0862AU, 0x930CA3U, 0xCEDD70U, 0x85E6CDU, 0x9D7196U, 0x562A63U, 0x6D9AE8U, 0x24411DU, 0x7F5246U, 0x76EBDBU, + 0x2DB928U, 0x2712E5U, 0x5E83D7U, 0x15D80AU, 0x0C6BD1U, 0x473170U, 0x54A02FU, 0xB99B9EU, 0xE34841U, 0xEAD090U, + 0xB1E33FU, 0xFA2866U, 0xE31991U, 0x88C208U, 0x8154FFU, 0xDB6FB7U, 0x92BE28U, 0x89A5D9U, 0xE25606U, 0x7BCE37U, + 0x30FDFCU, 0x693E21U, 0x6F2792U, 0x3495CFU, 0x5DCE6CU, 0x465DB1U, 0x0FA46AU, 0x14B75FU, 0x5F2D85U, 0x275C60U, + 0x2CC7FBU, 0xF56486U, 0xFE3C55U, 0xA5ABC8U, 0xECD02BU, 0xD743F2U, 0x9FDAC5U, 0xC0A81CU, 0xC33383U, 0x9A2262U, + 0xB1D93DU, 0xE8DA8DU, 0x232252U, 0x39B19BU, 0x70AAACU, 0x6B5975U, 0x024182U, 0x59921BU, 0x522974U, 0x0B38A5U, + 0x01F33EU, 0x78C1CBU, 0x3758D0U, 0x242F3DU, 0xEDB4EFU, 0xB66672U, 0xBF5701U, 0xC5CCDCU, 0xCE9F77U, 0x9726A2U, + 0xDCA4F9U, 0xC5FF4CU, 0xAE4E87U, 0xB51576U, 0xFDA7E9U, 0xA63C90U, 0x2F6D47U, 0x74D6CFU, 0x1BC538U, 0x0A1D21U, + 0x413EDEU, 0x58E50FU, 0x127480U, 0x6B4BF1U, 0x60992EU, 0x2BA297U, 0x327340U, 0x79E809U, 0xA0DABAU, 0x8A0367U, + 0xD1009DU, 0x98BB98U, 0x836A63U, 0xCE70F6U, 0xF5832DU, 0xB69850U, 0xEE29D3U, 0xE5732EU, 0xBCE0FDU, 0xB75962U, + 0x4C1A13U, 0x0589DCU, 0x1EF165U, 0x5666B7U, 0x4DFDEAU, 0x268E59U, 0x7F1794U, 0x74256FU, 0x29FE7AU, 0x626F81U, + 0x700404U, 0x1996DFU, 0x828FA2U, 0xCB7C31U, 0x9067CCU, 0x9B940EU, 0xE20C17U, 0xE81FE8U, 0xB1E439U, 0xFAF586U, + 0xE17FC7U, 0xA88C18U, 0xD397A1U, 0x5E4276U, 0x04794FU, 0x0FEB88U, 0x5E9271U, 0x3501E6U, 0x2C9A3EU, 0x67EA51U, + 0x7C61C0U, 0x34323BU, 0x6F89EEU, 0x4618F5U, 0x1D4218U, 0xD4F1CBU, 0xCFE876U, 0x841B25U, 0xB888F8U, 0xF3D053U, + 0xAA7386U, 0xA168BCU, 0xF2BB69U, 0xFB8792U, 0x80541FU, 0xC8CF4CU, 0xC3FEB5U, 0x182522U, 0x1117CBU, 0x6A9E9CU, + 0x234D05U, 0x3876FAU, 0x72A42BU, 0x2FBD84U, 0x240ED4U, 0x5DD54BU, 0x56C4B2U, 0x057E65U, 0x4C2D4CU, 0xD7849BU, + 0xBFD762U, 0xA44DF9U, 0xEFFEACU, 0xB6A347U, 0xBD30D2U, 0xC40B29U, 0x8FDB74U, 0x9540E6U, 0xDC330BU, 0xC3BAD8U, + 0x8A89E5U, 0x71533EU, 0x7AC0BBU, 0x2BB140U, 0x212A11U, 0x7838AEU, 0x13C17FU, 0x08D290U, 0x414989U, 0x1AA85EU, + 0x13B2A6U, 0x494131U, 0x625AD8U, 0xBBCF87U, 0xF43516U, 0xED26E9U, 0xA6BF78U, 0x9FCC17U, 0xDD57CEU, 0x86B75DU, + 0x8FACA0U, 0xD43FE3U, 0x9D445EU, 0xA6D584U, 0x6DCF71U, 0x753C6AU, 0x3EA5AFU, 0x67F654U, 0x4C4CC9U, 0x134DBAU, + 0x1AB667U, 0x4125E4U, 0x097E19U, 0x12CA0AU, 0x71D1F3U, 0x78022CU, 0xA33BACU, 0xEAA953U, 0xF17A02U, 0x9B53BDU, + 0xC28074U, 0xC9BB83U, 0x90299AU, 0x9BF04DU, 0xC4C3B4U, 0xAD583BU, 0xB7084AU, 0xFEB3D1U, 0x656004U, 0x2E69FEU, + 0x5FDAF3U, 0x548000U, 0x0D37DDU, 0x472E4EU, 0x5CFD33U, 0x1546F8U, 0x2E164DU, 0x678D96U, 0x3CBEE3U, 0x337768U, + 0xEBE5BDU, 0xC09E47U, 0x990D5EU, 0xD234A9U, 0xC9E720U, 0x887DF7U, 0xD34C0EU, 0xFB9711U, 0xA084E0U, 0xA96C2FU, + 0xF27FBEU, 0xB9E4C1U, 0x001318U, 0x4B02AFU, 0x56B867U, 0x1CEB30U, 0x477289U, 0x4E8152U, 0x358AF7U, 0x3C1AACU, + 0x676159U, 0x24F2C2U, 0x3C6917U, 0x57197CU, 0x8E82E1U, 0x85F112U, 0xDE68CFU, 0xD77BDDU, 0x8C9130U, 0xE400EBU, + 0xFB5B5EU, 0xB0E885U, 0xA9F6D4U, 0xE2277BU, 0x9B9CA2U, 0x108F15U, 0x5A764CU, 0x0B64ABU, 0x00AF32U, 0x599CEDU, + 0x72059DU, 0x29D702U, 0x60ECE3U, 0x7A7D3CU, 0x330625U, 0x0C95D6U, 0x474D0BU, 0x9E7EA8U, 0x95FDF5U, 0xCCA666U, + 0x86179BU, 0xBD8D40U, 0xFCDA65U, 0xE763BFU, 0xAE304AU, 0xF58AD1U, 0xDE9B9CU, 0x86406FU, 0x8DE3F2U, 0x54B801U, + 0x1B28D8U, 0x0213D7U, 0x69C026U, 0x7259B9U, 0x3A6B48U, 0x61B017U, 0x68819FU, 0x135A68U, 0x50D9B1U, 0x49E386U, + 0x02325FU, 0x9A29B0U, 0xD19E23U, 0xAAC77EU, 0xA3558DU, 0xFCAE04U, 0xF5BFF3U, 0xAE04AAU, 0xC44635U, 0xDDDDC5U, + 0x966C4AU, 0xCF373BU, 0xC4A4E4U, 0x1FD47DU, 0x3E4F8AU, 0x64DC43U, 0x2DA574U, 0x3637ADU, 0x7D5C56U, 0x44CFC3U, + 0x0BD688U, 0x52257DU, 0x59BBE7U, 0x03AA1AU, 0x4A5119U, 0xF142C4U, 0xB89A37U, 0xB329AAU, 0xE822D1U, 0xA9D114U, + 0x93C88FU, 0xDA5A7AU, 0xC1A121U, 0x8AB090U, 0xD36B5EU, 0xDC58A7U, 0xA5C0B0U, 0x2F8369U, 0x74389EU, 0x3DAB17U, + 0x26D368U, 0x4F40F9U, 0x141F26U, 0x1DAEC7U, 0x473558U, 0x446721U, 0x1DDEF6U, 0x769D6EU, 0xEF0E8DU, 0xA434D0U, + 0xBFE56BU, 0xF35EBEU, 0x884D45U, 0x819440U, 0xDAA69BU, 0x917D26U, 0x88ECF5U, 0xC3C788U, 0xFB150BU, 0xB02ED6U, + 0x63BF24U, 0x6A6439U, 0x3153D2U, 0x188B03U, 0x43989CU, 0x0923EDU, 0x147232U, 0x5FF99BU, 0x060B4CU, 0x2D10B5U, + 0x76A1A2U, 0x7FFA7BU, 0xA568D4U, 0xECD104U, 0xD7827BU, 0x9C19EAU, 0x8D6831U, 0xC6E2DCU, 0x9F71CFU, 0x950A32U, + 0xEE9BE1U, 0xA3A16CU, 0xB8761FU, 0xF16FC2U, 0x6A9C79U, 0x010FACU, 0x491786U, 0x52F453U, 0x1BEF88U, 0x007C35U, + 0x4B8566U, 0x32978FU, 0x316C18U, 0x697DC1U, 0x62E6BEU, 0x3B142FU, 0xD40DC0U, 0xCFCE11U, 0x86F58EU, 0xDD66F6U, + 0xD53E31U, 0x8E8988U, 0xA5125FU, 0xFC6366U, 0xB7F9B9U, 0xAEAA78U, 0xE513C3U, 0xD69096U, 0x1ECB6DU, 0x4579F8U, + 0x4C6033U, 0x13B34EU, 0x5888DCU, 0x615821U, 0x2AE3F2U, 0x32F0FFU, 0x792B04U, 0x220A91U, 0x0B906AU, 0xD0432BU, + 0xD97294U, 0x82AD4DU, 0xC8BE9AU, 0xD90623U, 0xB2D564U, 0xEBEE9CU, 0xE02D03U, 0xBF35D2U, 0xB686ADU, 0xCCDD2CU, + 0x854CD3U, 0x1EF70AU, 0x55A51DU, 0x4C1CE4U, 0x074F67U, 0x7ED49AU, 0x7476C9U, 0x2F2F75U, 0x26BCBEU, 0x75876BU, + 0x1C5650U, 0x07C885U, 0x48BB7EU, 0x9022F3U, 0x9B11A0U, 0xC2CA5DU, 0xE9C8CEU, 0xA07133U, 0xFBA238U, 0xF0B9E9U, + 0xA84917U, 0x835286U, 0xDAC179U, 0x913830U, 0x822B87U, 0x4BD95EU, 0x30D289U, 0x3C43A0U, 0x67B87FU, 0x6CAA8EU, + 0x353311U, 0x7E4440U, 0x47DFABU, 0x0C8E3FU, 0x1634C4U, 0x5FA7D9U, 0x04CC0AU, 0xAD5DE7U, 0xF64774U, 0xBDB409U, + 0xAC2DD2U, 0xE67E67U, 0xFBC5ACU, 0x90D5F9U, 0xCB0E42U, 0xC23D9FU, 0x99B67DU, 0x9047E4U, 0xEA5DB3U, 0x218E0AU, + 0x38B7D5U, 0x732034U, 0x6AFA2BU, 0x21CBFAU, 0x5A1005U, 0x5B039CU, 0x01A8FBU, 0x4C7822U, 0x574395U, 0x3CD04DU, + 0xA5811AU, 0xEE3BB3U, 0xB76868U, 0xBDF19DU, 0xE64286U, 0xCF1943U, 0x949BF8U, 0xDDA225U, 0xC67156U, 0x8FCACBU, + 0xF59B08U, 0xF605F5U, 0x2B36EFU, 0x20EF1AU, 0x797CC1U, 0x324664U, 0x1985BFU, 0x419CE4U, 0x4A6F51U, 0x13748AU, + 0x58C42FU, 0x631F74U, 0x2A0CA1U, 0x71F51AU, 0xF9E7D7U, 0xA27CA5U, 0xA99F38U, 0xD886EBU, 0x973516U, 0x8E6F1DU, + 0xC5FEECU, 0xDF0133U, 0xB61282U, 0xED8ADDU, 0xE4F954U, 0xBF7AA3U, 0x74617AU, 0x6D904DU, 0x070A95U, 0x1E795AU, + 0x55E0EBU, 0x0EF334U, 0x0F0845U, 0x7098CAU, 0x798313U, 0x2360E0U, 0x687BFDU, 0x71AB0EU, 0xBA10C3U, 0x830370U, + 0xC8FA2DU, 0x93EDB7U, 0x9B3742U, 0xC00689U, 0xA99DBCU, 0xB25E67U, 0xF964BAU, 0xE0F509U, 0xA7AE44U, 0xFF1DB7U, + 0x54C42EU, 0x0DF6F1U, 0x066D90U, 0x5D3C0EU, 0x1487FFU, 0x2F8460U, 0x675E19U, 0x3CEFDEU, 0x37B447U, 0x6E27B0U, + 0x651369U, 0x9CC856U, 0xD77B97U, 0xC9604CU, 0x88B1F9U, 0x939BA2U, 0xFA4856U, 0xB1D1DDU, 0xAAE200U, 0xE33873U, + 0xB829EEU, 0xB0D20DU, 0xCBC190U, 0x407AEBU, 0x19AA3EU, 0x52A1A5U, 0x4B1240U, 0x204B1BU, 0x3ED9A2U, 0x7F2274U, + 0x2437ADU, 0x2DAC8AU, 0x76DF53U, 0x5D45ACU, 0x04F43DU, 0xCEBFE2U, 0xD72CC3U, 0x9C551CU, 0xE7C7E5U, 0xEEDC72U, + 0xB52D1BU, 0xBCB6CCU, 0xE6A454U, 0xA95FA7U, 0x904EFAU, 0xD3A551U, 0xCA3684U, 0x01265FU, 0x5ADD6AU, 0x72CEB1U, + 0x29135CU, 0x60A1CFU, 0x7BBA92U, 0x304921U, 0x2950FCU, 0x42D316U, 0x1AA903U, 0x1138F8U, 0x48E329U, 0xC7D0A6U, + 0xBC48DFU, 0xFD1B08U, 0xE6A0B1U, 0xAE3366U, 0xF55AAFU, 0xFEC898U, 0x879341U, 0x8C22FEU, 0xD5392EU, 0x9EEA61U, + 0x8456D0U, 0x6D450BU, 0x769EF6U, 0x3FADE5U, 0x606508U, 0x6BD6DBU, 0x3ACD46U, 0x101C3DU, 0x5927F8U, 0x02F543U, + 0x096C96U, 0x505FCCU, 0xBB8C71U, 0xA296B2U, 0xE8370FU, 0xF36C5CU, 0xBADF85U, 0xE1063AU, 0xC814FBU, 0x97AF04U, + 0x9CFA15U, 0xC461EAU, 0x87D23BU, 0xBE88B4U, 0x7509CCU, 0x2E721BU, 0x27E1A2U, 0x7C5965U, 0x750A7CU, 0x0F9183U, + 0x44A052U, 0x5D7BE9U, 0x1669ACU, 0x0F9277U, 0x6013CAU, 0x3B0819U, 0xB3FA65U, 0xE0E3E6U, 0xA9103BU, 0xB28BC0U, + 0xDB9ED5U, 0xC0642EU, 0x8B77EBU, 0xD3EC50U, 0xD80D89U, 0xA1179EU, 0xAAC477U, 0xF1F5A0U, 0x386E19U, 0x271D4FU, + 0x6F8596U, 0x541639U, 0x1F6DE8U, 0x4EFE97U, 0x45B706U, 0x1C05D9U, 0x779E30U, 0x6DCF27U, 0x2474DEU, 0x3F664DU, + 0xF69BB0U, 0xAD08FBU, 0x86536FU, 0xDFE094U, 0xD1E841U, 0x883B6AU, 0xC300B7U, 0xE8D164U, 0xB16BD9U, 0xF2788AU, + 0xEBA167U, 0xA192FCU, 0x3A0929U, 0x53DBD2U, 0x08F2C3U, 0x01212DU, 0x5A3ABCU, 0x518B43U, 0x29D11AU, 0x62628DU, + 0x7FFD64U, 0x34ACB3U, 0x6F1E8AU, 0xE64555U, 0x95C494U, 0x9D7F2BU, 0xC62C7AU, 0x8DB485U, 0x94871DU, 0xFF5CDEU, + 0xE6EFE3U, 0xADB730U, 0xF524CFU, 0xFE0F56U, 0xA5DE31U, 0x48C5E8U, 0x53377FU, 0x1AAE86U, 0x01BD59U, 0x4B4678U, + 0x3A50A7U, 0x31E977U, 0x683ACCU, 0x633189U, 0x38C072U, 0x71DAEFU, 0x4B493CU, 0x82B001U, 0x99A3C2U, 0xD2383FU, + 0x8F4AA4U, 0xA4D3D1U, 0xFDA00AU, 0xB62B8FU, 0xACBB75U, 0xE5C028U, 0xF6539BU, 0x9F4242U, 0xC4B985U, 0x4F2FBCU, + 0x167463U, 0x1CC5D2U, 0x65DE1DU, 0x2E3C4CU, 0x35A5F3U, 0x78F622U, 0x234DDDU, 0x0A5C55U, 0x408622U, 0x5BB5FBU, + 0x122E6CU, 0xC1FF95U, 0xC8C4DEU, 0xB3066BU, 0xB83FB0U, 0xE0AC25U, 0xAB775EU, 0xB24793U, 0xD9DC20U, 0x828BFDU, + 0x8F30AFU, 0xD46102U, 0xDCDBD9U, 0x07582CU, 0x6E0137U, 0x75B2C6U, 0x3EE809U, 0x2F7990U, 0x64C2E7U, 0x1C913EU, + 0x170A89U, 0x4C3A40U, 0x45E9D6U, 0x1E42AFU, 0x571370U, 0xE889C1U, 0xA2BA0EU, 0xFB635FU, 0xF070E0U, 0xA9CF39U, + 0x821DDAU, 0xD904C7U, 0x90F734U, 0x82FCE9U, 0xCB4D72U, 0xD09716U, 0x3B848DU, 0x623D78U, 0x696EA3U, 0x30F4BEU, + 0x7A075DU, 0x451E80U, 0x0C8D33U, 0x17E66EU, 0x5E76B5U, 0x050D14U, 0x0E9ECBU, 0x7607BAU, 0xF57524U, 0xACEAC5U, + 0xE7F91AU, 0xFC0083U, 0x9583F4U, 0xCED96DU, 0xC6688AU, 0x9D7353U, 0x92804CU, 0xCB11BDU, 0xA00B62U, 0xA9F8C3U, + 0x72E398U, 0x783244U, 0x2118F7U, 0x4A8B2AU, 0x5B5249U, 0x1061D4U, 0x09FA2FU, 0x428ABAU, 0x1911F1U, 0x31C604U, + 0x6AFD9FU, 0x276D62U, 0xBC2631U, 0xF795B8U, 0xCE4C4EU, 0x855F97U, 0xDDE520U, 0xD6B479U, 0x8D0FB6U, 0x8C1C07U, + 0xF7C6D8U, 0xBE77A9U, 0xA53C36U, 0xEFAFDFU, 0x369648U, 0x1D4411U, 0x40DFE6U, 0x4BEE7EU, 0x103595U, 0x5902C0U, + 0x43D85BU, 0x2AC9AEU, 0x316265U, 0x7AB158U, 0x23A18BU, 0x201A56U, 0xD949E5U, 0x93F2A8U, 0x882313U, 0xC139C6U, + 0xDA8A3CU, 0x97D329U, 0xEC50E2U, 0xE7AA13U, 0xBFBB8CU, 0xB42075U, 0xED5322U, 0x06C8ABU, 0x1DF85CU, 0x542785U, + 0x0FB4BAU, 0x0FCD7BU, 0x544FA4U, 0x7F5414U, 0x26A54BU, 0x6D3EF2U, 0x702D31U, 0x3BD7CCU, 0x13C6DFU, 0xC83D02U, + 0x83AEF9U, 0x9AB77CU, 0xD15507U, 0xC84ED2U, 0xA3DF49U, 0xF9A4BDU, 0xF836F6U, 0xA3ED4BU, 0xEADC98U, 0xD14B05U, + 0x9A30E6U, 0x03A0BFU, 0x4D6B00U, 0x1458D1U, 0x1FC12EU, 0x64932FU, 0x6D28F0U, 0x36BB09U, 0x7FE29FU, 0x6551E6U, + 0x0E0B21U, 0x57AAB8U, 0x54B147U, 0x8D6216U, 0x86DBA9U, 0xDDC968U, 0xB412F3U, 0xAA218EU, 0xE3FC5DU, 0xF86EF0U, + 0xB35523U, 0xCA945FU, 0xC1AFCCU, 0x983C11U, 0xD264FAU, 0x49D7EFU, 0x000C14U, 0x3B1FC1U, 0x7AA75AU, 0x21F4B7U, + 0x2A6FA4U, 0x728E5DU, 0x5D958AU, 0x042713U, 0x4F767DU, 0x54EDACU, 0x1D5E13U, 0x8604C0U, 0xEE91ADU, 0xB5EA36U, + 0xBC79E3U, 0xE77018U, 0xAC820DU, 0x9D19E6U, 0xD6283FU, 0xCEF3A8U, 0x85E0D1U, 0xDA1A47U, 0x538BAEU, 0x389079U, + 0x216360U, 0x6A6B9FU, 0x30D84EU, 0x3903E1U, 0x421230U, 0x0BE94FU, 0x10FBD6U, 0x5B6011U, 0x4215E8U, 0x008EFBU, + 0xF95C07U, 0xF2759CU, 0xADE659U, 0xA49D22U, 0xFF0CB7U, 0x96964CU, 0x8CE591U, 0xC77E92U, 0x9E2F6FU, 0x959CBCU, + 0xCC0601U, 0xE7475AU, 0x3CFCBFU, 0x74EF25U, 0x6717F4U, 0x2E048BU, 0x15DF0AU, 0x5A6CF5U, 0x03716CU, 0x08A33BU, + 0x5098C2U, 0x5B1945U, 0x20C2BCU, 0x69F063U, 0xF22972U, 0xBB1A8DU, 0xE0814DU, 0xCA52F6U, 0x936AABU, 0x98B958U, + 0xC9A2C5U, 0x820306U, 0x9B593BU, 0xF4CAE0U, 0xEE7315U, 0xA7209EU, 0x7C9BCBU, 0x75C930U, 0x0E54A4U, 0x45E75FU, + 0x5CBC12U, 0x173D81U, 0x0F0778U, 0x44D4AFU, 0x3FC596U, 0x363E59U, 0x65ACE8U, 0x6C9737U, 0xA346E6U, 0xD95DD9U, + 0xD0FE10U, 0x8B26E6U, 0xC2357FU, 0xD9CE28U, 0x92DDC1U, 0xAB455EU, 0xE1B6AFU, 0xB8ADF4U, 0xB35861U, 0x68438AU, + 0x41C157U, 0x12B864U, 0x5B2BB9U, 0x45B00AU, 0x0EC3C6U, 0x175B95U, 0x7C2828U, 0x25B3F3U, 0x2E2206U, 0x75580DU, + 0x3DDBD8U, 0x86C223U, 0xCF31BAU, 0xD4AADDU, 0x9FF804U, 0xC64193U, 0xCD526AU, 0xBDA9F4U, 0xB2BD95U, 0xE92E4AU, + 0xA0C5FBU, 0xBBD424U, 0xD20F7DU, 0x093DDAU, 0x01A603U, 0x5A77F0U, 0x514CEDU, 0x089E36U, 0x63A7D3U, 0x7A3448U, + 0x31FF3CU, 0x2BCEE7U, 0x625462U, 0x150799U, 0x1CBC84U, 0xC7ED77U, 0x8C76AAU, 0x95C409U, 0xDF9954U, 0xE62A8FU, + 0xAD213EU, 0xF6F1E1U, 0xFF4A00U, 0xA4191EU, 0x8D82C7U, 0xD7B330U, 0x9C69A9U, 0x057ACEU, 0x42C357U, 0x2B1088U, + 0x303A79U, 0x7BEB76U, 0x63F087U, 0x284358U, 0x7198E1U, 0x5A88B2U, 0x017B7EU, 0x0860CDU, 0x53F510U, 0x9A0F63U, + 0xA00CFEU, 0xEBB535U, 0xF2E6C0U, 0xB97DDBU, 0xEC0F2EU, 0xE796B5U, 0x9C0578U, 0xD47E0BU, 0xCFEF92U, 0x86F564U, + 0x1D16ADU, 0x768F32U, 0x2FFC43U, 0x24669CU, 0x7C752DU, 0x778CE2U, 0x2E1F9BU, 0x45000CU, 0x5EF0D5U, 0x13FB62U, + 0x40282BU, 0x4811D4U, 0xB38344U, 0xB8789FU, 0xE16BEAU, 0xAAB261U, 0xB38194U, 0xF81B4FU, 0xC2CA52U, 0x8BE1B1U, + 0xD0726CU, 0xD903DFU, 0x829982U, 0xE94A79U, 0x7471FDU, 0x36E026U, 0x2FBA93U, 0x640DC8U, 0x3F1431U, 0x16D7B6U, + 0x4D6C6FU, 0x443C18U, 0x1E8781U, 0x55947EU, 0x6C4FBFU, 0x27FFA0U, 0xBEE451U, 0xF5378FU, 0xAE0E2EU, 0xA2CD71U, + 0xC9D7C8U, 0x98661FU, 0x93BDC6U, 0xC88EE5U, 0xC15438U, 0xBA45C3U, 0xF2FE56U, 0xE9290DU, 0x2230E8U, 0x3B9273U, + 0x70C98FU, 0x0958DCU, 0x02A343U, 0x58B0A2U, 0x150A7DU, 0x0E5BC4U, 0x6FC897U, 0x74F33AU, 0x3F23E9U, 0x66A834U, + 0xECDB0FU, 0xB542DAU, 0x9E5131U, 0xC7ABA5U, 0x8C38FEU, 0x97010BU, 0xDED290U, 0xA4CC7DU, 0xAD3D2EU, 0xF6B6B3U, + 0xF9A540U, 0x205ED9U, 0x634EB6U, 0x5A9567U, 0x11A6D8U, 0x0B3F09U }; + + const uint32_t AMBE_A_TABLE[] = { + 0U, 4U, 8U, 12U, 16U, 20U, 24U, 28U, 32U, 36U, 40U, 44U, + 48U, 52U, 56U, 60U, 64U, 68U, 1U, 5U, 9U, 13U, 17U, 21U }; + const uint32_t AMBE_B_TABLE[] = { + 25U, 29U, 33U, 37U, 41U, 45U, 49U, 53U, 57U, 61U, 65U, 69U, + 2U, 6U, 10U, 14U, 18U, 22U, 26U, 30U, 34U, 38U, 42U }; + const uint32_t AMBE_C_TABLE[] = { + 46U, 50U, 54U, 58U, 62U, 66U, 70U, 3U, 7U, 11U, 15U, 19U, + 23U, 27U, 31U, 35U, 39U, 43U, 47U, 51U, 55U, 59U, 63U, 67U, 71U }; + + const uint32_t IMBE_INTERLEAVE[] = { + 0, 7, 12, 19, 24, 31, 36, 43, 48, 55, 60, 67, 72, 79, 84, 91, 96, 103, 108, 115, 120, 127, 132, 139, + 1, 6, 13, 18, 25, 30, 37, 42, 49, 54, 61, 66, 73, 78, 85, 90, 97, 102, 109, 114, 121, 126, 133, 138, + 2, 9, 14, 21, 26, 33, 38, 45, 50, 57, 62, 69, 74, 81, 86, 93, 98, 105, 110, 117, 122, 129, 134, 141, + 3, 8, 15, 20, 27, 32, 39, 44, 51, 56, 63, 68, 75, 80, 87, 92, 99, 104, 111, 116, 123, 128, 135, 140, + 4, 11, 16, 23, 28, 35, 40, 47, 52, 59, 64, 71, 76, 83, 88, 95, 100, 107, 112, 119, 124, 131, 136, 143, + 5, 10, 17, 22, 29, 34, 41, 46, 53, 58, 65, 70, 77, 82, 89, 94, 101, 106, 113, 118, 125, 130, 137, 142 }; + + // --------------------------------------------------------------------------- + // Class Declaration + // --------------------------------------------------------------------------- + + /** + * @brief Implements routines to regenerate AMBE/IMBE data using forward error + * correction. + * @ingroup edac + */ + class HOST_SW_API AMBEFEC { + public: + /** + * @brief Initializes a new instance of the AMBEFEC class. + */ + AMBEFEC(); + /** + * @brief Finalizes a instance of the AMBEFEC class. + */ + ~AMBEFEC(); + + /** + * @brief Regenerates the DMR AMBE FEC for the input bytes. + * @param bytes AMBE bytes. + * @returns uint32_t Count of errors. + */ + uint32_t regenerateDMR(uint8_t* bytes) const; + /** + * @brief Returns the number of errors on the DMR BER input bytes. + * @param[in] bytes AMBE bytes. + * @returns uint32_t Count of errors. + */ + uint32_t measureDMRBER(const uint8_t* bytes) const; + + /** + * @brief Regenerates the P25 IMBE FEC for the input bytes. + * @param bytes IMBE bytes. + * @returns Count of errors. + */ + uint32_t regenerateIMBE(uint8_t* bytes) const; + /** + * @brief Returns the number of errors on the P25 BER input bytes. + * @param[in] bytes AMBE bytes. + * @returns uint32_t Count of errors. + */ + uint32_t measureP25BER(const uint8_t* bytes) const; + + /** + * @brief Regenerates the NXDN AMBE FEC for the input bytes. + * @param bytes AMBE bytes. + * @returns uint32_t Count of errors. + */ + uint32_t regenerateNXDN(uint8_t* bytes) const; + /** + * @brief Returns the number of errors on the NXDN BER input bytes. + * @param[in] bytes AMBE bytes. + * @returns uint32_t Count of errors. + */ + uint32_t measureNXDNBER(uint8_t* bytes) const; + + private: + /** + * @brief + * @param a + * @param b + * @param c + * @returns uint32_t Count of errors. + */ + uint32_t regenerate(uint32_t& a, uint32_t& b, uint32_t& c) const; + }; +} // namespace edac + +#endif // __AMBE_FEC_H__ diff --git a/vocoder/CMakeLists.txt b/vocoder/CMakeLists.txt new file mode 100644 index 0000000..d5a2b85 --- /dev/null +++ b/vocoder/CMakeLists.txt @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-only +#/* +# * Digital Voice Modem - Remote Command Client +# * GPLv2 Open Source. Use is subject to license terms. +# * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# * +# * Copyright (C) 2024 Bryan Biedenkapp, N2PLL +# * +# */ +file(GLOB vocoder_SRC + "vocoder/imbe/*.cpp" + "vocoder/*.cpp" + "vocoder/*.c" +) + +file(GLOB vocoder_INCLUDE + "vocoder/imbe/*.h" + "vocoder/*.h" +) diff --git a/vocoder/Defines.h b/vocoder/Defines.h new file mode 100644 index 0000000..01190b2 --- /dev/null +++ b/vocoder/Defines.h @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - Common Library + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX + * Copyright (C) 2018-2024 Bryan Biedenkapp, N2PLL + * + */ +/** + * @defgroup common Common Library + * @brief Digital Voice Modem - Common Library + * @details This library implements common core code used by the majority of dvmhost projects. + * @ingroup common + * + * @defgroup edac Error Detection and Correction + * @brief Implementation for various Error Detection and Correction methods. + * @ingroup common + * + * @file Defines.h + * @ingroup common + */ +#if !defined(__COMMON_DEFINES_H__) +#define __COMMON_DEFINES_H__ + +#include +#include +#include +#include +#include +#include + +// --------------------------------------------------------------------------- +// Types +// --------------------------------------------------------------------------- + +#ifndef _INT8_T_DECLARED +#ifndef __INT8_TYPE__ +typedef signed char int8_t; +#endif // __INT8_TYPE__ +#endif // _INT8_T_DECLARED +#ifndef _INT16_T_DECLARED +#ifndef __INT16_TYPE__ +typedef short int16_t; +#endif // __INT16_TYPE__ +#endif // _INT16_T_DECLARED +#ifndef _INT32_T_DECLARED +#ifndef __INT32_TYPE__ +typedef int int32_t; +#endif // __INT32_TYPE__ +#endif // _INT32_T_DECLARED +#ifndef _INT64_T_DECLARED +#ifndef __INT64_TYPE__ +typedef long long int64_t; +#endif // __INT64_TYPE__ +#endif // _INT64_T_DECLARED +#ifndef _UINT8_T_DECLARED +#ifndef __UINT8_TYPE__ +typedef unsigned char uint8_t; +#endif // __UINT8_TYPE__ +#endif // _UINT8_T_DECLARED +#ifndef _UINT16_T_DECLARED +#ifndef __UINT16_TYPE__ +typedef unsigned short uint16_t; +#endif // __UINT16_TYPE__ +#endif // _UINT16_T_DECLARED +#ifndef _UINT32_T_DECLARED +#ifndef __UINT32_TYPE__ +typedef unsigned int uint32_t; +#endif // __UINT32_TYPE__ +#endif // _UINT32_T_DECLARED +#ifndef _UINT64_T_DECLARED +#ifndef __UINT64_TYPE__ +typedef unsigned long long uint64_t; +#endif // __UINT64_TYPE__ +#endif // _UINT64_T_DECLARED + +#ifndef __LONG64_TYPE__ +typedef long long long64_t; +#endif // __LONG64_TYPE__ +#ifndef __ULONG64_TYPE__ +typedef unsigned long long ulong64_t; +#endif // __ULONG64_TYPE__ + +#if defined(__GNUC__) || defined(__GNUG__) +#define __forceinline __attribute__((always_inline)) +#endif + +#if defined(__MINGW32__) || defined(__MINGW64__) || defined(__GNUC__) || defined(__GNUG__) +#define PACK(decl) decl __attribute__((__packed__)) +#else +#define PACK(decl) __pragma(pack(push, 1)) decl __pragma(pack(pop)) +#endif + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +#ifndef __GIT_VER__ +#define __GIT_VER__ "00000000" +#endif +#ifndef __GIT_VER_HASH__ +#define __GIT_VER_HASH__ "00000000" +#endif + +#define __PROG_NAME__ "" +#define __EXE_NAME__ "" + +#define VERSION_MAJOR "04" +#define VERSION_MINOR "11" +#define VERSION_REV "F" + +#define __NETVER__ "DVM_R" VERSION_MAJOR VERSION_REV VERSION_MINOR +#define __VER__ VERSION_MAJOR "." VERSION_MINOR VERSION_REV " (R" VERSION_MAJOR VERSION_REV VERSION_MINOR " " __GIT_VER__ ")" + +#define __BUILD__ __DATE__ " " __TIME__ +#if !defined(NDEBUG) +#undef __BUILD__ +#define __BUILD__ __DATE__ " " __TIME__ " DEBUG_FACTORY_LABTOOL" +#endif // DEBUG + +#define __BANNER__ "\r\n" \ +" . . \r\n" \ +"8 888888888o. `8.`888b ,8' ,8. ,8. \r\n" \ +"8 8888 `^888. `8.`888b ,8' ,888. ,888. \r\n" \ +"8 8888 `88.`8.`888b ,8' .`8888. .`8888. \r\n" \ +"8 8888 `88 `8.`888b ,8' ,8.`8888. ,8.`8888. \r\n" \ +"8 8888 88 `8.`888b ,8' ,8'8.`8888,8^8.`8888. \r\n" \ +"8 8888 88 `8.`888b ,8' ,8' `8.`8888' `8.`8888. \r\n" \ +"8 8888 ,88 `8.`888b8' ,8' `8.`88' `8.`8888. \r\n" \ +"8 8888 ,88' `8.`888' ,8' `8.`' `8.`8888. \r\n" \ +"8 8888 ,o88P' `8.`8' ,8' `8 `8.`8888. \r\n" \ +"8 888888888P' `8.` ,8' ` `8.`8888. \r\n" + +#define HOST_SW_API + +/** + * @addtogroup common + * @{ + */ + +#define DEFAULT_CONF_FILE "config.yml" +#define DEFAULT_LOCK_FILE "/tmp/dvm.lock" + +#define NULL_PORT "null" +#define UART_PORT "uart" +#define PTY_PORT "pty" + +#define MODEM_MODE_AIR "air" +#define MODEM_MODE_DFSI "dfsi" + +const uint32_t REMOTE_MODEM_PORT = 3334; +const uint32_t TRAFFIC_DEFAULT_PORT = 62031; +const uint32_t REST_API_DEFAULT_PORT = 9990; + +/** + * @brief Operational Host States + */ +enum HOST_STATE { + FNE_STATE = 240U, //! FNE (only used by dvmfne) + + HOST_STATE_LOCKOUT = 250U, //! Lockout (dvmhost traffic lockout state) + HOST_STATE_ERROR = 254U, //! Error (dvmhost error state) + HOST_STATE_QUIT = 255U, //! Quit (dvmhost quit state) +}; + +/** + * @brief Operational RF States + */ +enum RPT_RF_STATE { + RS_RF_LISTENING, //! Modem Listening + RS_RF_LATE_ENTRY, //! Traffic Late Entry + RS_RF_AUDIO, //! Audio + RS_RF_DATA, //! Data + RS_RF_REJECTED, //! Traffic Rejected + RS_RF_INVALID //! Traffic Invalid +}; + +/** + * @brief Operational Network States + */ +enum RPT_NET_STATE { + RS_NET_IDLE, //! Idle + RS_NET_AUDIO, //! Audio + RS_NET_DATA //! Data +}; + +const uint8_t UDP_COMPRESS_NONE = 0x00U; + +const uint8_t IP_COMPRESS_NONE = 0x00U; +const uint8_t IP_COMPRESS_RFC1144_COMPRESS = 0x01U; +const uint8_t IP_COMPRESS_RFC1144_UNCOMPRESS = 0x02U; + +// --------------------------------------------------------------------------- +// Class Helper Macros +// --------------------------------------------------------------------------- + +/** + * Class Copy Code Pattern + */ + +/** + * @brief Creates a private copy implementation. + * This requires the copy(const type& data) to be declared in the class definition. + * @param type Atomic type. + */ +#define __COPY(type) \ + private: virtual void copy(const type& data); \ + public: __forceinline type& operator=(const type& data) { \ + if (this != &data) { \ + copy(data); \ + } \ + return *this; \ + } +/** + * @brief Creates a protected copy implementation. + * This requires the copy(const type& data) to be declared in the class definition. + * @param type Atomic type. + */ +#define __PROTECTED_COPY(type) \ + protected: virtual void copy(const type& data); \ + public: __forceinline type& operator=(const type& data) { \ + if (this != &data) { \ + copy(data); \ + } \ + return *this; \ + } + +/** + * Property Creation + * These macros should always be used LAST in the "public" section of a class definition. + */ + +/** + * @brief Creates a read-only get property. + * @param type Atomic type for property. + * @param variableName Variable name for property. + * @param propName Property name. + */ +#define __READONLY_PROPERTY(type, variableName, propName) \ + private: type m_##variableName; \ + public: __forceinline type get##propName(void) const { return m_##variableName; } +/** + * @brief Creates a read-only get property. + * @param type Atomic type for property. + * @param variableName Variable name for property. + * @param propName Property name. + */ +#define __PROTECTED_READONLY_PROPERTY(type, variableName, propName) \ + protected: type m_##variableName; \ + public: __forceinline type get##propName(void) const { return m_##variableName; } + +/** + * @brief Creates a read-only get property, does not use "get". + * @param type Atomic type for property. + * @param variableName Variable name for property. + */ +#define __PROTECTED_READONLY_PROPERTY_PLAIN(type, variableName) \ + protected: type m_##variableName; \ + public: __forceinline type variableName(void) const { return m_##variableName; } +/** + * @brief Creates a read-only get property, does not use "get". + * @param type Atomic type for property. + * @param variableName Variable name for property. + */ +#define __READONLY_PROPERTY_PLAIN(type, variableName) \ + private: type m_##variableName; \ + public: __forceinline type variableName(void) const { return m_##variableName; } + +/** + * @brief Creates a get and set private property. + * @param type Atomic type for property. + * @param variableName Variable name for property. + * @param propName Property name. + */ +#define __PROPERTY(type, variableName, propName) \ + private: type m_##variableName; \ + public: __forceinline type get##propName(void) const { return m_##variableName; } \ + __forceinline void set##propName(type val) { m_##variableName = val; } +/** + * @brief Creates a get and set protected property. + * @param type Atomic type for property. + * @param variableName Variable name for property. + * @param propName Property name. + */ +#define __PROTECTED_PROPERTY(type, variableName, propName) \ + protected: type m_##variableName; \ + public: __forceinline type get##propName(void) const { return m_##variableName; } \ + __forceinline void set##propName(type val) { m_##variableName = val; } + +/** + * @brief Creates a get and set private property, does not use "get"/"set". + * @param type Atomic type for property. + * @param variableName Variable name for property. + */ +#define __PROPERTY_PLAIN(type, variableName) \ + private: type m_##variableName; \ + public: __forceinline type variableName(void) const { return m_##variableName; }\ + __forceinline void variableName(type val) { m_##variableName = val; } +/** + * @brief Creates a get and set protected property, does not use "get"/"set". + * @param type Atomic type for property. + * @param variableName Variable name for property. + */ +#define __PROTECTED_PROPERTY_PLAIN(type, variableName) \ + protected: type m_##variableName; \ + public: __forceinline type variableName(void) const { return m_##variableName; }\ + __forceinline void variableName(type val) { m_##variableName = val; } + +/** @} */ +#endif // __COMMON_DEFINES_H__ diff --git a/vocoder/Golay24128.cpp b/vocoder/Golay24128.cpp new file mode 100644 index 0000000..9a95094 --- /dev/null +++ b/vocoder/Golay24128.cpp @@ -0,0 +1,1256 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - Common Library + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright (C) 2002 by Robert H. Morelos-Zaragoza., All rights reserved. + * Copyright (C) 2010,2016 Jonathan Naylor, G4KLX + * Copyright (C) 2017 Bryan Biedenkapp, N2PLL + * + */ +#include "Defines.h" +#include "Golay24128.h" +#include "Utils.h" + +using namespace edac; + +#include + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +const uint32_t ENCODING_TABLE_23127[] = { + 0x000000U, 0x0018EAU, 0x00293EU, 0x0031D4U, 0x004A96U, 0x00527CU, 0x0063A8U, 0x007B42U, 0x008DC6U, 0x00952CU, + 0x00A4F8U, 0x00BC12U, 0x00C750U, 0x00DFBAU, 0x00EE6EU, 0x00F684U, 0x010366U, 0x011B8CU, 0x012A58U, 0x0132B2U, + 0x0149F0U, 0x01511AU, 0x0160CEU, 0x017824U, 0x018EA0U, 0x01964AU, 0x01A79EU, 0x01BF74U, 0x01C436U, 0x01DCDCU, + 0x01ED08U, 0x01F5E2U, 0x0206CCU, 0x021E26U, 0x022FF2U, 0x023718U, 0x024C5AU, 0x0254B0U, 0x026564U, 0x027D8EU, + 0x028B0AU, 0x0293E0U, 0x02A234U, 0x02BADEU, 0x02C19CU, 0x02D976U, 0x02E8A2U, 0x02F048U, 0x0305AAU, 0x031D40U, + 0x032C94U, 0x03347EU, 0x034F3CU, 0x0357D6U, 0x036602U, 0x037EE8U, 0x03886CU, 0x039086U, 0x03A152U, 0x03B9B8U, + 0x03C2FAU, 0x03DA10U, 0x03EBC4U, 0x03F32EU, 0x040D98U, 0x041572U, 0x0424A6U, 0x043C4CU, 0x04470EU, 0x045FE4U, + 0x046E30U, 0x0476DAU, 0x04805EU, 0x0498B4U, 0x04A960U, 0x04B18AU, 0x04CAC8U, 0x04D222U, 0x04E3F6U, 0x04FB1CU, + 0x050EFEU, 0x051614U, 0x0527C0U, 0x053F2AU, 0x054468U, 0x055C82U, 0x056D56U, 0x0575BCU, 0x058338U, 0x059BD2U, + 0x05AA06U, 0x05B2ECU, 0x05C9AEU, 0x05D144U, 0x05E090U, 0x05F87AU, 0x060B54U, 0x0613BEU, 0x06226AU, 0x063A80U, + 0x0641C2U, 0x065928U, 0x0668FCU, 0x067016U, 0x068692U, 0x069E78U, 0x06AFACU, 0x06B746U, 0x06CC04U, 0x06D4EEU, + 0x06E53AU, 0x06FDD0U, 0x070832U, 0x0710D8U, 0x07210CU, 0x0739E6U, 0x0742A4U, 0x075A4EU, 0x076B9AU, 0x077370U, + 0x0785F4U, 0x079D1EU, 0x07ACCAU, 0x07B420U, 0x07CF62U, 0x07D788U, 0x07E65CU, 0x07FEB6U, 0x0803DAU, 0x081B30U, + 0x082AE4U, 0x08320EU, 0x08494CU, 0x0851A6U, 0x086072U, 0x087898U, 0x088E1CU, 0x0896F6U, 0x08A722U, 0x08BFC8U, + 0x08C48AU, 0x08DC60U, 0x08EDB4U, 0x08F55EU, 0x0900BCU, 0x091856U, 0x092982U, 0x093168U, 0x094A2AU, 0x0952C0U, + 0x096314U, 0x097BFEU, 0x098D7AU, 0x099590U, 0x09A444U, 0x09BCAEU, 0x09C7ECU, 0x09DF06U, 0x09EED2U, 0x09F638U, + 0x0A0516U, 0x0A1DFCU, 0x0A2C28U, 0x0A34C2U, 0x0A4F80U, 0x0A576AU, 0x0A66BEU, 0x0A7E54U, 0x0A88D0U, 0x0A903AU, + 0x0AA1EEU, 0x0AB904U, 0x0AC246U, 0x0ADAACU, 0x0AEB78U, 0x0AF392U, 0x0B0670U, 0x0B1E9AU, 0x0B2F4EU, 0x0B37A4U, + 0x0B4CE6U, 0x0B540CU, 0x0B65D8U, 0x0B7D32U, 0x0B8BB6U, 0x0B935CU, 0x0BA288U, 0x0BBA62U, 0x0BC120U, 0x0BD9CAU, + 0x0BE81EU, 0x0BF0F4U, 0x0C0E42U, 0x0C16A8U, 0x0C277CU, 0x0C3F96U, 0x0C44D4U, 0x0C5C3EU, 0x0C6DEAU, 0x0C7500U, + 0x0C8384U, 0x0C9B6EU, 0x0CAABAU, 0x0CB250U, 0x0CC912U, 0x0CD1F8U, 0x0CE02CU, 0x0CF8C6U, 0x0D0D24U, 0x0D15CEU, + 0x0D241AU, 0x0D3CF0U, 0x0D47B2U, 0x0D5F58U, 0x0D6E8CU, 0x0D7666U, 0x0D80E2U, 0x0D9808U, 0x0DA9DCU, 0x0DB136U, + 0x0DCA74U, 0x0DD29EU, 0x0DE34AU, 0x0DFBA0U, 0x0E088EU, 0x0E1064U, 0x0E21B0U, 0x0E395AU, 0x0E4218U, 0x0E5AF2U, + 0x0E6B26U, 0x0E73CCU, 0x0E8548U, 0x0E9DA2U, 0x0EAC76U, 0x0EB49CU, 0x0ECFDEU, 0x0ED734U, 0x0EE6E0U, 0x0EFE0AU, + 0x0F0BE8U, 0x0F1302U, 0x0F22D6U, 0x0F3A3CU, 0x0F417EU, 0x0F5994U, 0x0F6840U, 0x0F70AAU, 0x0F862EU, 0x0F9EC4U, + 0x0FAF10U, 0x0FB7FAU, 0x0FCCB8U, 0x0FD452U, 0x0FE586U, 0x0FFD6CU, 0x1007B4U, 0x101F5EU, 0x102E8AU, 0x103660U, + 0x104D22U, 0x1055C8U, 0x10641CU, 0x107CF6U, 0x108A72U, 0x109298U, 0x10A34CU, 0x10BBA6U, 0x10C0E4U, 0x10D80EU, + 0x10E9DAU, 0x10F130U, 0x1104D2U, 0x111C38U, 0x112DECU, 0x113506U, 0x114E44U, 0x1156AEU, 0x11677AU, 0x117F90U, + 0x118914U, 0x1191FEU, 0x11A02AU, 0x11B8C0U, 0x11C382U, 0x11DB68U, 0x11EABCU, 0x11F256U, 0x120178U, 0x121992U, + 0x122846U, 0x1230ACU, 0x124BEEU, 0x125304U, 0x1262D0U, 0x127A3AU, 0x128CBEU, 0x129454U, 0x12A580U, 0x12BD6AU, + 0x12C628U, 0x12DEC2U, 0x12EF16U, 0x12F7FCU, 0x13021EU, 0x131AF4U, 0x132B20U, 0x1333CAU, 0x134888U, 0x135062U, + 0x1361B6U, 0x13795CU, 0x138FD8U, 0x139732U, 0x13A6E6U, 0x13BE0CU, 0x13C54EU, 0x13DDA4U, 0x13EC70U, 0x13F49AU, + 0x140A2CU, 0x1412C6U, 0x142312U, 0x143BF8U, 0x1440BAU, 0x145850U, 0x146984U, 0x14716EU, 0x1487EAU, 0x149F00U, + 0x14AED4U, 0x14B63EU, 0x14CD7CU, 0x14D596U, 0x14E442U, 0x14FCA8U, 0x15094AU, 0x1511A0U, 0x152074U, 0x15389EU, + 0x1543DCU, 0x155B36U, 0x156AE2U, 0x157208U, 0x15848CU, 0x159C66U, 0x15ADB2U, 0x15B558U, 0x15CE1AU, 0x15D6F0U, + 0x15E724U, 0x15FFCEU, 0x160CE0U, 0x16140AU, 0x1625DEU, 0x163D34U, 0x164676U, 0x165E9CU, 0x166F48U, 0x1677A2U, + 0x168126U, 0x1699CCU, 0x16A818U, 0x16B0F2U, 0x16CBB0U, 0x16D35AU, 0x16E28EU, 0x16FA64U, 0x170F86U, 0x17176CU, + 0x1726B8U, 0x173E52U, 0x174510U, 0x175DFAU, 0x176C2EU, 0x1774C4U, 0x178240U, 0x179AAAU, 0x17AB7EU, 0x17B394U, + 0x17C8D6U, 0x17D03CU, 0x17E1E8U, 0x17F902U, 0x18046EU, 0x181C84U, 0x182D50U, 0x1835BAU, 0x184EF8U, 0x185612U, + 0x1867C6U, 0x187F2CU, 0x1889A8U, 0x189142U, 0x18A096U, 0x18B87CU, 0x18C33EU, 0x18DBD4U, 0x18EA00U, 0x18F2EAU, + 0x190708U, 0x191FE2U, 0x192E36U, 0x1936DCU, 0x194D9EU, 0x195574U, 0x1964A0U, 0x197C4AU, 0x198ACEU, 0x199224U, + 0x19A3F0U, 0x19BB1AU, 0x19C058U, 0x19D8B2U, 0x19E966U, 0x19F18CU, 0x1A02A2U, 0x1A1A48U, 0x1A2B9CU, 0x1A3376U, + 0x1A4834U, 0x1A50DEU, 0x1A610AU, 0x1A79E0U, 0x1A8F64U, 0x1A978EU, 0x1AA65AU, 0x1ABEB0U, 0x1AC5F2U, 0x1ADD18U, + 0x1AECCCU, 0x1AF426U, 0x1B01C4U, 0x1B192EU, 0x1B28FAU, 0x1B3010U, 0x1B4B52U, 0x1B53B8U, 0x1B626CU, 0x1B7A86U, + 0x1B8C02U, 0x1B94E8U, 0x1BA53CU, 0x1BBDD6U, 0x1BC694U, 0x1BDE7EU, 0x1BEFAAU, 0x1BF740U, 0x1C09F6U, 0x1C111CU, + 0x1C20C8U, 0x1C3822U, 0x1C4360U, 0x1C5B8AU, 0x1C6A5EU, 0x1C72B4U, 0x1C8430U, 0x1C9CDAU, 0x1CAD0EU, 0x1CB5E4U, + 0x1CCEA6U, 0x1CD64CU, 0x1CE798U, 0x1CFF72U, 0x1D0A90U, 0x1D127AU, 0x1D23AEU, 0x1D3B44U, 0x1D4006U, 0x1D58ECU, + 0x1D6938U, 0x1D71D2U, 0x1D8756U, 0x1D9FBCU, 0x1DAE68U, 0x1DB682U, 0x1DCDC0U, 0x1DD52AU, 0x1DE4FEU, 0x1DFC14U, + 0x1E0F3AU, 0x1E17D0U, 0x1E2604U, 0x1E3EEEU, 0x1E45ACU, 0x1E5D46U, 0x1E6C92U, 0x1E7478U, 0x1E82FCU, 0x1E9A16U, + 0x1EABC2U, 0x1EB328U, 0x1EC86AU, 0x1ED080U, 0x1EE154U, 0x1EF9BEU, 0x1F0C5CU, 0x1F14B6U, 0x1F2562U, 0x1F3D88U, + 0x1F46CAU, 0x1F5E20U, 0x1F6FF4U, 0x1F771EU, 0x1F819AU, 0x1F9970U, 0x1FA8A4U, 0x1FB04EU, 0x1FCB0CU, 0x1FD3E6U, + 0x1FE232U, 0x1FFAD8U, 0x200F68U, 0x201782U, 0x202656U, 0x203EBCU, 0x2045FEU, 0x205D14U, 0x206CC0U, 0x20742AU, + 0x2082AEU, 0x209A44U, 0x20AB90U, 0x20B37AU, 0x20C838U, 0x20D0D2U, 0x20E106U, 0x20F9ECU, 0x210C0EU, 0x2114E4U, + 0x212530U, 0x213DDAU, 0x214698U, 0x215E72U, 0x216FA6U, 0x21774CU, 0x2181C8U, 0x219922U, 0x21A8F6U, 0x21B01CU, + 0x21CB5EU, 0x21D3B4U, 0x21E260U, 0x21FA8AU, 0x2209A4U, 0x22114EU, 0x22209AU, 0x223870U, 0x224332U, 0x225BD8U, + 0x226A0CU, 0x2272E6U, 0x228462U, 0x229C88U, 0x22AD5CU, 0x22B5B6U, 0x22CEF4U, 0x22D61EU, 0x22E7CAU, 0x22FF20U, + 0x230AC2U, 0x231228U, 0x2323FCU, 0x233B16U, 0x234054U, 0x2358BEU, 0x23696AU, 0x237180U, 0x238704U, 0x239FEEU, + 0x23AE3AU, 0x23B6D0U, 0x23CD92U, 0x23D578U, 0x23E4ACU, 0x23FC46U, 0x2402F0U, 0x241A1AU, 0x242BCEU, 0x243324U, + 0x244866U, 0x24508CU, 0x246158U, 0x2479B2U, 0x248F36U, 0x2497DCU, 0x24A608U, 0x24BEE2U, 0x24C5A0U, 0x24DD4AU, + 0x24EC9EU, 0x24F474U, 0x250196U, 0x25197CU, 0x2528A8U, 0x253042U, 0x254B00U, 0x2553EAU, 0x25623EU, 0x257AD4U, + 0x258C50U, 0x2594BAU, 0x25A56EU, 0x25BD84U, 0x25C6C6U, 0x25DE2CU, 0x25EFF8U, 0x25F712U, 0x26043CU, 0x261CD6U, + 0x262D02U, 0x2635E8U, 0x264EAAU, 0x265640U, 0x266794U, 0x267F7EU, 0x2689FAU, 0x269110U, 0x26A0C4U, 0x26B82EU, + 0x26C36CU, 0x26DB86U, 0x26EA52U, 0x26F2B8U, 0x27075AU, 0x271FB0U, 0x272E64U, 0x27368EU, 0x274DCCU, 0x275526U, + 0x2764F2U, 0x277C18U, 0x278A9CU, 0x279276U, 0x27A3A2U, 0x27BB48U, 0x27C00AU, 0x27D8E0U, 0x27E934U, 0x27F1DEU, + 0x280CB2U, 0x281458U, 0x28258CU, 0x283D66U, 0x284624U, 0x285ECEU, 0x286F1AU, 0x2877F0U, 0x288174U, 0x28999EU, + 0x28A84AU, 0x28B0A0U, 0x28CBE2U, 0x28D308U, 0x28E2DCU, 0x28FA36U, 0x290FD4U, 0x29173EU, 0x2926EAU, 0x293E00U, + 0x294542U, 0x295DA8U, 0x296C7CU, 0x297496U, 0x298212U, 0x299AF8U, 0x29AB2CU, 0x29B3C6U, 0x29C884U, 0x29D06EU, + 0x29E1BAU, 0x29F950U, 0x2A0A7EU, 0x2A1294U, 0x2A2340U, 0x2A3BAAU, 0x2A40E8U, 0x2A5802U, 0x2A69D6U, 0x2A713CU, + 0x2A87B8U, 0x2A9F52U, 0x2AAE86U, 0x2AB66CU, 0x2ACD2EU, 0x2AD5C4U, 0x2AE410U, 0x2AFCFAU, 0x2B0918U, 0x2B11F2U, + 0x2B2026U, 0x2B38CCU, 0x2B438EU, 0x2B5B64U, 0x2B6AB0U, 0x2B725AU, 0x2B84DEU, 0x2B9C34U, 0x2BADE0U, 0x2BB50AU, + 0x2BCE48U, 0x2BD6A2U, 0x2BE776U, 0x2BFF9CU, 0x2C012AU, 0x2C19C0U, 0x2C2814U, 0x2C30FEU, 0x2C4BBCU, 0x2C5356U, + 0x2C6282U, 0x2C7A68U, 0x2C8CECU, 0x2C9406U, 0x2CA5D2U, 0x2CBD38U, 0x2CC67AU, 0x2CDE90U, 0x2CEF44U, 0x2CF7AEU, + 0x2D024CU, 0x2D1AA6U, 0x2D2B72U, 0x2D3398U, 0x2D48DAU, 0x2D5030U, 0x2D61E4U, 0x2D790EU, 0x2D8F8AU, 0x2D9760U, + 0x2DA6B4U, 0x2DBE5EU, 0x2DC51CU, 0x2DDDF6U, 0x2DEC22U, 0x2DF4C8U, 0x2E07E6U, 0x2E1F0CU, 0x2E2ED8U, 0x2E3632U, + 0x2E4D70U, 0x2E559AU, 0x2E644EU, 0x2E7CA4U, 0x2E8A20U, 0x2E92CAU, 0x2EA31EU, 0x2EBBF4U, 0x2EC0B6U, 0x2ED85CU, + 0x2EE988U, 0x2EF162U, 0x2F0480U, 0x2F1C6AU, 0x2F2DBEU, 0x2F3554U, 0x2F4E16U, 0x2F56FCU, 0x2F6728U, 0x2F7FC2U, + 0x2F8946U, 0x2F91ACU, 0x2FA078U, 0x2FB892U, 0x2FC3D0U, 0x2FDB3AU, 0x2FEAEEU, 0x2FF204U, 0x3008DCU, 0x301036U, + 0x3021E2U, 0x303908U, 0x30424AU, 0x305AA0U, 0x306B74U, 0x30739EU, 0x30851AU, 0x309DF0U, 0x30AC24U, 0x30B4CEU, + 0x30CF8CU, 0x30D766U, 0x30E6B2U, 0x30FE58U, 0x310BBAU, 0x311350U, 0x312284U, 0x313A6EU, 0x31412CU, 0x3159C6U, + 0x316812U, 0x3170F8U, 0x31867CU, 0x319E96U, 0x31AF42U, 0x31B7A8U, 0x31CCEAU, 0x31D400U, 0x31E5D4U, 0x31FD3EU, + 0x320E10U, 0x3216FAU, 0x32272EU, 0x323FC4U, 0x324486U, 0x325C6CU, 0x326DB8U, 0x327552U, 0x3283D6U, 0x329B3CU, + 0x32AAE8U, 0x32B202U, 0x32C940U, 0x32D1AAU, 0x32E07EU, 0x32F894U, 0x330D76U, 0x33159CU, 0x332448U, 0x333CA2U, + 0x3347E0U, 0x335F0AU, 0x336EDEU, 0x337634U, 0x3380B0U, 0x33985AU, 0x33A98EU, 0x33B164U, 0x33CA26U, 0x33D2CCU, + 0x33E318U, 0x33FBF2U, 0x340544U, 0x341DAEU, 0x342C7AU, 0x343490U, 0x344FD2U, 0x345738U, 0x3466ECU, 0x347E06U, + 0x348882U, 0x349068U, 0x34A1BCU, 0x34B956U, 0x34C214U, 0x34DAFEU, 0x34EB2AU, 0x34F3C0U, 0x350622U, 0x351EC8U, + 0x352F1CU, 0x3537F6U, 0x354CB4U, 0x35545EU, 0x35658AU, 0x357D60U, 0x358BE4U, 0x35930EU, 0x35A2DAU, 0x35BA30U, + 0x35C172U, 0x35D998U, 0x35E84CU, 0x35F0A6U, 0x360388U, 0x361B62U, 0x362AB6U, 0x36325CU, 0x36491EU, 0x3651F4U, + 0x366020U, 0x3678CAU, 0x368E4EU, 0x3696A4U, 0x36A770U, 0x36BF9AU, 0x36C4D8U, 0x36DC32U, 0x36EDE6U, 0x36F50CU, + 0x3700EEU, 0x371804U, 0x3729D0U, 0x37313AU, 0x374A78U, 0x375292U, 0x376346U, 0x377BACU, 0x378D28U, 0x3795C2U, + 0x37A416U, 0x37BCFCU, 0x37C7BEU, 0x37DF54U, 0x37EE80U, 0x37F66AU, 0x380B06U, 0x3813ECU, 0x382238U, 0x383AD2U, + 0x384190U, 0x38597AU, 0x3868AEU, 0x387044U, 0x3886C0U, 0x389E2AU, 0x38AFFEU, 0x38B714U, 0x38CC56U, 0x38D4BCU, + 0x38E568U, 0x38FD82U, 0x390860U, 0x39108AU, 0x39215EU, 0x3939B4U, 0x3942F6U, 0x395A1CU, 0x396BC8U, 0x397322U, + 0x3985A6U, 0x399D4CU, 0x39AC98U, 0x39B472U, 0x39CF30U, 0x39D7DAU, 0x39E60EU, 0x39FEE4U, 0x3A0DCAU, 0x3A1520U, + 0x3A24F4U, 0x3A3C1EU, 0x3A475CU, 0x3A5FB6U, 0x3A6E62U, 0x3A7688U, 0x3A800CU, 0x3A98E6U, 0x3AA932U, 0x3AB1D8U, + 0x3ACA9AU, 0x3AD270U, 0x3AE3A4U, 0x3AFB4EU, 0x3B0EACU, 0x3B1646U, 0x3B2792U, 0x3B3F78U, 0x3B443AU, 0x3B5CD0U, + 0x3B6D04U, 0x3B75EEU, 0x3B836AU, 0x3B9B80U, 0x3BAA54U, 0x3BB2BEU, 0x3BC9FCU, 0x3BD116U, 0x3BE0C2U, 0x3BF828U, + 0x3C069EU, 0x3C1E74U, 0x3C2FA0U, 0x3C374AU, 0x3C4C08U, 0x3C54E2U, 0x3C6536U, 0x3C7DDCU, 0x3C8B58U, 0x3C93B2U, + 0x3CA266U, 0x3CBA8CU, 0x3CC1CEU, 0x3CD924U, 0x3CE8F0U, 0x3CF01AU, 0x3D05F8U, 0x3D1D12U, 0x3D2CC6U, 0x3D342CU, + 0x3D4F6EU, 0x3D5784U, 0x3D6650U, 0x3D7EBAU, 0x3D883EU, 0x3D90D4U, 0x3DA100U, 0x3DB9EAU, 0x3DC2A8U, 0x3DDA42U, + 0x3DEB96U, 0x3DF37CU, 0x3E0052U, 0x3E18B8U, 0x3E296CU, 0x3E3186U, 0x3E4AC4U, 0x3E522EU, 0x3E63FAU, 0x3E7B10U, + 0x3E8D94U, 0x3E957EU, 0x3EA4AAU, 0x3EBC40U, 0x3EC702U, 0x3EDFE8U, 0x3EEE3CU, 0x3EF6D6U, 0x3F0334U, 0x3F1BDEU, + 0x3F2A0AU, 0x3F32E0U, 0x3F49A2U, 0x3F5148U, 0x3F609CU, 0x3F7876U, 0x3F8EF2U, 0x3F9618U, 0x3FA7CCU, 0x3FBF26U, + 0x3FC464U, 0x3FDC8EU, 0x3FED5AU, 0x3FF5B0U, 0x40063AU, 0x401ED0U, 0x402F04U, 0x4037EEU, 0x404CACU, 0x405446U, + 0x406592U, 0x407D78U, 0x408BFCU, 0x409316U, 0x40A2C2U, 0x40BA28U, 0x40C16AU, 0x40D980U, 0x40E854U, 0x40F0BEU, + 0x41055CU, 0x411DB6U, 0x412C62U, 0x413488U, 0x414FCAU, 0x415720U, 0x4166F4U, 0x417E1EU, 0x41889AU, 0x419070U, + 0x41A1A4U, 0x41B94EU, 0x41C20CU, 0x41DAE6U, 0x41EB32U, 0x41F3D8U, 0x4200F6U, 0x42181CU, 0x4229C8U, 0x423122U, + 0x424A60U, 0x42528AU, 0x42635EU, 0x427BB4U, 0x428D30U, 0x4295DAU, 0x42A40EU, 0x42BCE4U, 0x42C7A6U, 0x42DF4CU, + 0x42EE98U, 0x42F672U, 0x430390U, 0x431B7AU, 0x432AAEU, 0x433244U, 0x434906U, 0x4351ECU, 0x436038U, 0x4378D2U, + 0x438E56U, 0x4396BCU, 0x43A768U, 0x43BF82U, 0x43C4C0U, 0x43DC2AU, 0x43EDFEU, 0x43F514U, 0x440BA2U, 0x441348U, + 0x44229CU, 0x443A76U, 0x444134U, 0x4459DEU, 0x44680AU, 0x4470E0U, 0x448664U, 0x449E8EU, 0x44AF5AU, 0x44B7B0U, + 0x44CCF2U, 0x44D418U, 0x44E5CCU, 0x44FD26U, 0x4508C4U, 0x45102EU, 0x4521FAU, 0x453910U, 0x454252U, 0x455AB8U, + 0x456B6CU, 0x457386U, 0x458502U, 0x459DE8U, 0x45AC3CU, 0x45B4D6U, 0x45CF94U, 0x45D77EU, 0x45E6AAU, 0x45FE40U, + 0x460D6EU, 0x461584U, 0x462450U, 0x463CBAU, 0x4647F8U, 0x465F12U, 0x466EC6U, 0x46762CU, 0x4680A8U, 0x469842U, + 0x46A996U, 0x46B17CU, 0x46CA3EU, 0x46D2D4U, 0x46E300U, 0x46FBEAU, 0x470E08U, 0x4716E2U, 0x472736U, 0x473FDCU, + 0x47449EU, 0x475C74U, 0x476DA0U, 0x47754AU, 0x4783CEU, 0x479B24U, 0x47AAF0U, 0x47B21AU, 0x47C958U, 0x47D1B2U, + 0x47E066U, 0x47F88CU, 0x4805E0U, 0x481D0AU, 0x482CDEU, 0x483434U, 0x484F76U, 0x48579CU, 0x486648U, 0x487EA2U, + 0x488826U, 0x4890CCU, 0x48A118U, 0x48B9F2U, 0x48C2B0U, 0x48DA5AU, 0x48EB8EU, 0x48F364U, 0x490686U, 0x491E6CU, + 0x492FB8U, 0x493752U, 0x494C10U, 0x4954FAU, 0x49652EU, 0x497DC4U, 0x498B40U, 0x4993AAU, 0x49A27EU, 0x49BA94U, + 0x49C1D6U, 0x49D93CU, 0x49E8E8U, 0x49F002U, 0x4A032CU, 0x4A1BC6U, 0x4A2A12U, 0x4A32F8U, 0x4A49BAU, 0x4A5150U, + 0x4A6084U, 0x4A786EU, 0x4A8EEAU, 0x4A9600U, 0x4AA7D4U, 0x4ABF3EU, 0x4AC47CU, 0x4ADC96U, 0x4AED42U, 0x4AF5A8U, + 0x4B004AU, 0x4B18A0U, 0x4B2974U, 0x4B319EU, 0x4B4ADCU, 0x4B5236U, 0x4B63E2U, 0x4B7B08U, 0x4B8D8CU, 0x4B9566U, + 0x4BA4B2U, 0x4BBC58U, 0x4BC71AU, 0x4BDFF0U, 0x4BEE24U, 0x4BF6CEU, 0x4C0878U, 0x4C1092U, 0x4C2146U, 0x4C39ACU, + 0x4C42EEU, 0x4C5A04U, 0x4C6BD0U, 0x4C733AU, 0x4C85BEU, 0x4C9D54U, 0x4CAC80U, 0x4CB46AU, 0x4CCF28U, 0x4CD7C2U, + 0x4CE616U, 0x4CFEFCU, 0x4D0B1EU, 0x4D13F4U, 0x4D2220U, 0x4D3ACAU, 0x4D4188U, 0x4D5962U, 0x4D68B6U, 0x4D705CU, + 0x4D86D8U, 0x4D9E32U, 0x4DAFE6U, 0x4DB70CU, 0x4DCC4EU, 0x4DD4A4U, 0x4DE570U, 0x4DFD9AU, 0x4E0EB4U, 0x4E165EU, + 0x4E278AU, 0x4E3F60U, 0x4E4422U, 0x4E5CC8U, 0x4E6D1CU, 0x4E75F6U, 0x4E8372U, 0x4E9B98U, 0x4EAA4CU, 0x4EB2A6U, + 0x4EC9E4U, 0x4ED10EU, 0x4EE0DAU, 0x4EF830U, 0x4F0DD2U, 0x4F1538U, 0x4F24ECU, 0x4F3C06U, 0x4F4744U, 0x4F5FAEU, + 0x4F6E7AU, 0x4F7690U, 0x4F8014U, 0x4F98FEU, 0x4FA92AU, 0x4FB1C0U, 0x4FCA82U, 0x4FD268U, 0x4FE3BCU, 0x4FFB56U, + 0x50018EU, 0x501964U, 0x5028B0U, 0x50305AU, 0x504B18U, 0x5053F2U, 0x506226U, 0x507ACCU, 0x508C48U, 0x5094A2U, + 0x50A576U, 0x50BD9CU, 0x50C6DEU, 0x50DE34U, 0x50EFE0U, 0x50F70AU, 0x5102E8U, 0x511A02U, 0x512BD6U, 0x51333CU, + 0x51487EU, 0x515094U, 0x516140U, 0x5179AAU, 0x518F2EU, 0x5197C4U, 0x51A610U, 0x51BEFAU, 0x51C5B8U, 0x51DD52U, + 0x51EC86U, 0x51F46CU, 0x520742U, 0x521FA8U, 0x522E7CU, 0x523696U, 0x524DD4U, 0x52553EU, 0x5264EAU, 0x527C00U, + 0x528A84U, 0x52926EU, 0x52A3BAU, 0x52BB50U, 0x52C012U, 0x52D8F8U, 0x52E92CU, 0x52F1C6U, 0x530424U, 0x531CCEU, + 0x532D1AU, 0x5335F0U, 0x534EB2U, 0x535658U, 0x53678CU, 0x537F66U, 0x5389E2U, 0x539108U, 0x53A0DCU, 0x53B836U, + 0x53C374U, 0x53DB9EU, 0x53EA4AU, 0x53F2A0U, 0x540C16U, 0x5414FCU, 0x542528U, 0x543DC2U, 0x544680U, 0x545E6AU, + 0x546FBEU, 0x547754U, 0x5481D0U, 0x54993AU, 0x54A8EEU, 0x54B004U, 0x54CB46U, 0x54D3ACU, 0x54E278U, 0x54FA92U, + 0x550F70U, 0x55179AU, 0x55264EU, 0x553EA4U, 0x5545E6U, 0x555D0CU, 0x556CD8U, 0x557432U, 0x5582B6U, 0x559A5CU, + 0x55AB88U, 0x55B362U, 0x55C820U, 0x55D0CAU, 0x55E11EU, 0x55F9F4U, 0x560ADAU, 0x561230U, 0x5623E4U, 0x563B0EU, + 0x56404CU, 0x5658A6U, 0x566972U, 0x567198U, 0x56871CU, 0x569FF6U, 0x56AE22U, 0x56B6C8U, 0x56CD8AU, 0x56D560U, + 0x56E4B4U, 0x56FC5EU, 0x5709BCU, 0x571156U, 0x572082U, 0x573868U, 0x57432AU, 0x575BC0U, 0x576A14U, 0x5772FEU, + 0x57847AU, 0x579C90U, 0x57AD44U, 0x57B5AEU, 0x57CEECU, 0x57D606U, 0x57E7D2U, 0x57FF38U, 0x580254U, 0x581ABEU, + 0x582B6AU, 0x583380U, 0x5848C2U, 0x585028U, 0x5861FCU, 0x587916U, 0x588F92U, 0x589778U, 0x58A6ACU, 0x58BE46U, + 0x58C504U, 0x58DDEEU, 0x58EC3AU, 0x58F4D0U, 0x590132U, 0x5919D8U, 0x59280CU, 0x5930E6U, 0x594BA4U, 0x59534EU, + 0x59629AU, 0x597A70U, 0x598CF4U, 0x59941EU, 0x59A5CAU, 0x59BD20U, 0x59C662U, 0x59DE88U, 0x59EF5CU, 0x59F7B6U, + 0x5A0498U, 0x5A1C72U, 0x5A2DA6U, 0x5A354CU, 0x5A4E0EU, 0x5A56E4U, 0x5A6730U, 0x5A7FDAU, 0x5A895EU, 0x5A91B4U, + 0x5AA060U, 0x5AB88AU, 0x5AC3C8U, 0x5ADB22U, 0x5AEAF6U, 0x5AF21CU, 0x5B07FEU, 0x5B1F14U, 0x5B2EC0U, 0x5B362AU, + 0x5B4D68U, 0x5B5582U, 0x5B6456U, 0x5B7CBCU, 0x5B8A38U, 0x5B92D2U, 0x5BA306U, 0x5BBBECU, 0x5BC0AEU, 0x5BD844U, + 0x5BE990U, 0x5BF17AU, 0x5C0FCCU, 0x5C1726U, 0x5C26F2U, 0x5C3E18U, 0x5C455AU, 0x5C5DB0U, 0x5C6C64U, 0x5C748EU, + 0x5C820AU, 0x5C9AE0U, 0x5CAB34U, 0x5CB3DEU, 0x5CC89CU, 0x5CD076U, 0x5CE1A2U, 0x5CF948U, 0x5D0CAAU, 0x5D1440U, + 0x5D2594U, 0x5D3D7EU, 0x5D463CU, 0x5D5ED6U, 0x5D6F02U, 0x5D77E8U, 0x5D816CU, 0x5D9986U, 0x5DA852U, 0x5DB0B8U, + 0x5DCBFAU, 0x5DD310U, 0x5DE2C4U, 0x5DFA2EU, 0x5E0900U, 0x5E11EAU, 0x5E203EU, 0x5E38D4U, 0x5E4396U, 0x5E5B7CU, + 0x5E6AA8U, 0x5E7242U, 0x5E84C6U, 0x5E9C2CU, 0x5EADF8U, 0x5EB512U, 0x5ECE50U, 0x5ED6BAU, 0x5EE76EU, 0x5EFF84U, + 0x5F0A66U, 0x5F128CU, 0x5F2358U, 0x5F3BB2U, 0x5F40F0U, 0x5F581AU, 0x5F69CEU, 0x5F7124U, 0x5F87A0U, 0x5F9F4AU, + 0x5FAE9EU, 0x5FB674U, 0x5FCD36U, 0x5FD5DCU, 0x5FE408U, 0x5FFCE2U, 0x600952U, 0x6011B8U, 0x60206CU, 0x603886U, + 0x6043C4U, 0x605B2EU, 0x606AFAU, 0x607210U, 0x608494U, 0x609C7EU, 0x60ADAAU, 0x60B540U, 0x60CE02U, 0x60D6E8U, + 0x60E73CU, 0x60FFD6U, 0x610A34U, 0x6112DEU, 0x61230AU, 0x613BE0U, 0x6140A2U, 0x615848U, 0x61699CU, 0x617176U, + 0x6187F2U, 0x619F18U, 0x61AECCU, 0x61B626U, 0x61CD64U, 0x61D58EU, 0x61E45AU, 0x61FCB0U, 0x620F9EU, 0x621774U, + 0x6226A0U, 0x623E4AU, 0x624508U, 0x625DE2U, 0x626C36U, 0x6274DCU, 0x628258U, 0x629AB2U, 0x62AB66U, 0x62B38CU, + 0x62C8CEU, 0x62D024U, 0x62E1F0U, 0x62F91AU, 0x630CF8U, 0x631412U, 0x6325C6U, 0x633D2CU, 0x63466EU, 0x635E84U, + 0x636F50U, 0x6377BAU, 0x63813EU, 0x6399D4U, 0x63A800U, 0x63B0EAU, 0x63CBA8U, 0x63D342U, 0x63E296U, 0x63FA7CU, + 0x6404CAU, 0x641C20U, 0x642DF4U, 0x64351EU, 0x644E5CU, 0x6456B6U, 0x646762U, 0x647F88U, 0x64890CU, 0x6491E6U, + 0x64A032U, 0x64B8D8U, 0x64C39AU, 0x64DB70U, 0x64EAA4U, 0x64F24EU, 0x6507ACU, 0x651F46U, 0x652E92U, 0x653678U, + 0x654D3AU, 0x6555D0U, 0x656404U, 0x657CEEU, 0x658A6AU, 0x659280U, 0x65A354U, 0x65BBBEU, 0x65C0FCU, 0x65D816U, + 0x65E9C2U, 0x65F128U, 0x660206U, 0x661AECU, 0x662B38U, 0x6633D2U, 0x664890U, 0x66507AU, 0x6661AEU, 0x667944U, + 0x668FC0U, 0x66972AU, 0x66A6FEU, 0x66BE14U, 0x66C556U, 0x66DDBCU, 0x66EC68U, 0x66F482U, 0x670160U, 0x67198AU, + 0x67285EU, 0x6730B4U, 0x674BF6U, 0x67531CU, 0x6762C8U, 0x677A22U, 0x678CA6U, 0x67944CU, 0x67A598U, 0x67BD72U, + 0x67C630U, 0x67DEDAU, 0x67EF0EU, 0x67F7E4U, 0x680A88U, 0x681262U, 0x6823B6U, 0x683B5CU, 0x68401EU, 0x6858F4U, + 0x686920U, 0x6871CAU, 0x68874EU, 0x689FA4U, 0x68AE70U, 0x68B69AU, 0x68CDD8U, 0x68D532U, 0x68E4E6U, 0x68FC0CU, + 0x6909EEU, 0x691104U, 0x6920D0U, 0x69383AU, 0x694378U, 0x695B92U, 0x696A46U, 0x6972ACU, 0x698428U, 0x699CC2U, + 0x69AD16U, 0x69B5FCU, 0x69CEBEU, 0x69D654U, 0x69E780U, 0x69FF6AU, 0x6A0C44U, 0x6A14AEU, 0x6A257AU, 0x6A3D90U, + 0x6A46D2U, 0x6A5E38U, 0x6A6FECU, 0x6A7706U, 0x6A8182U, 0x6A9968U, 0x6AA8BCU, 0x6AB056U, 0x6ACB14U, 0x6AD3FEU, + 0x6AE22AU, 0x6AFAC0U, 0x6B0F22U, 0x6B17C8U, 0x6B261CU, 0x6B3EF6U, 0x6B45B4U, 0x6B5D5EU, 0x6B6C8AU, 0x6B7460U, + 0x6B82E4U, 0x6B9A0EU, 0x6BABDAU, 0x6BB330U, 0x6BC872U, 0x6BD098U, 0x6BE14CU, 0x6BF9A6U, 0x6C0710U, 0x6C1FFAU, + 0x6C2E2EU, 0x6C36C4U, 0x6C4D86U, 0x6C556CU, 0x6C64B8U, 0x6C7C52U, 0x6C8AD6U, 0x6C923CU, 0x6CA3E8U, 0x6CBB02U, + 0x6CC040U, 0x6CD8AAU, 0x6CE97EU, 0x6CF194U, 0x6D0476U, 0x6D1C9CU, 0x6D2D48U, 0x6D35A2U, 0x6D4EE0U, 0x6D560AU, + 0x6D67DEU, 0x6D7F34U, 0x6D89B0U, 0x6D915AU, 0x6DA08EU, 0x6DB864U, 0x6DC326U, 0x6DDBCCU, 0x6DEA18U, 0x6DF2F2U, + 0x6E01DCU, 0x6E1936U, 0x6E28E2U, 0x6E3008U, 0x6E4B4AU, 0x6E53A0U, 0x6E6274U, 0x6E7A9EU, 0x6E8C1AU, 0x6E94F0U, + 0x6EA524U, 0x6EBDCEU, 0x6EC68CU, 0x6EDE66U, 0x6EEFB2U, 0x6EF758U, 0x6F02BAU, 0x6F1A50U, 0x6F2B84U, 0x6F336EU, + 0x6F482CU, 0x6F50C6U, 0x6F6112U, 0x6F79F8U, 0x6F8F7CU, 0x6F9796U, 0x6FA642U, 0x6FBEA8U, 0x6FC5EAU, 0x6FDD00U, + 0x6FECD4U, 0x6FF43EU, 0x700EE6U, 0x70160CU, 0x7027D8U, 0x703F32U, 0x704470U, 0x705C9AU, 0x706D4EU, 0x7075A4U, + 0x708320U, 0x709BCAU, 0x70AA1EU, 0x70B2F4U, 0x70C9B6U, 0x70D15CU, 0x70E088U, 0x70F862U, 0x710D80U, 0x71156AU, + 0x7124BEU, 0x713C54U, 0x714716U, 0x715FFCU, 0x716E28U, 0x7176C2U, 0x718046U, 0x7198ACU, 0x71A978U, 0x71B192U, + 0x71CAD0U, 0x71D23AU, 0x71E3EEU, 0x71FB04U, 0x72082AU, 0x7210C0U, 0x722114U, 0x7239FEU, 0x7242BCU, 0x725A56U, + 0x726B82U, 0x727368U, 0x7285ECU, 0x729D06U, 0x72ACD2U, 0x72B438U, 0x72CF7AU, 0x72D790U, 0x72E644U, 0x72FEAEU, + 0x730B4CU, 0x7313A6U, 0x732272U, 0x733A98U, 0x7341DAU, 0x735930U, 0x7368E4U, 0x73700EU, 0x73868AU, 0x739E60U, + 0x73AFB4U, 0x73B75EU, 0x73CC1CU, 0x73D4F6U, 0x73E522U, 0x73FDC8U, 0x74037EU, 0x741B94U, 0x742A40U, 0x7432AAU, + 0x7449E8U, 0x745102U, 0x7460D6U, 0x74783CU, 0x748EB8U, 0x749652U, 0x74A786U, 0x74BF6CU, 0x74C42EU, 0x74DCC4U, + 0x74ED10U, 0x74F5FAU, 0x750018U, 0x7518F2U, 0x752926U, 0x7531CCU, 0x754A8EU, 0x755264U, 0x7563B0U, 0x757B5AU, + 0x758DDEU, 0x759534U, 0x75A4E0U, 0x75BC0AU, 0x75C748U, 0x75DFA2U, 0x75EE76U, 0x75F69CU, 0x7605B2U, 0x761D58U, + 0x762C8CU, 0x763466U, 0x764F24U, 0x7657CEU, 0x76661AU, 0x767EF0U, 0x768874U, 0x76909EU, 0x76A14AU, 0x76B9A0U, + 0x76C2E2U, 0x76DA08U, 0x76EBDCU, 0x76F336U, 0x7706D4U, 0x771E3EU, 0x772FEAU, 0x773700U, 0x774C42U, 0x7754A8U, + 0x77657CU, 0x777D96U, 0x778B12U, 0x7793F8U, 0x77A22CU, 0x77BAC6U, 0x77C184U, 0x77D96EU, 0x77E8BAU, 0x77F050U, + 0x780D3CU, 0x7815D6U, 0x782402U, 0x783CE8U, 0x7847AAU, 0x785F40U, 0x786E94U, 0x78767EU, 0x7880FAU, 0x789810U, + 0x78A9C4U, 0x78B12EU, 0x78CA6CU, 0x78D286U, 0x78E352U, 0x78FBB8U, 0x790E5AU, 0x7916B0U, 0x792764U, 0x793F8EU, + 0x7944CCU, 0x795C26U, 0x796DF2U, 0x797518U, 0x79839CU, 0x799B76U, 0x79AAA2U, 0x79B248U, 0x79C90AU, 0x79D1E0U, + 0x79E034U, 0x79F8DEU, 0x7A0BF0U, 0x7A131AU, 0x7A22CEU, 0x7A3A24U, 0x7A4166U, 0x7A598CU, 0x7A6858U, 0x7A70B2U, + 0x7A8636U, 0x7A9EDCU, 0x7AAF08U, 0x7AB7E2U, 0x7ACCA0U, 0x7AD44AU, 0x7AE59EU, 0x7AFD74U, 0x7B0896U, 0x7B107CU, + 0x7B21A8U, 0x7B3942U, 0x7B4200U, 0x7B5AEAU, 0x7B6B3EU, 0x7B73D4U, 0x7B8550U, 0x7B9DBAU, 0x7BAC6EU, 0x7BB484U, + 0x7BCFC6U, 0x7BD72CU, 0x7BE6F8U, 0x7BFE12U, 0x7C00A4U, 0x7C184EU, 0x7C299AU, 0x7C3170U, 0x7C4A32U, 0x7C52D8U, + 0x7C630CU, 0x7C7BE6U, 0x7C8D62U, 0x7C9588U, 0x7CA45CU, 0x7CBCB6U, 0x7CC7F4U, 0x7CDF1EU, 0x7CEECAU, 0x7CF620U, + 0x7D03C2U, 0x7D1B28U, 0x7D2AFCU, 0x7D3216U, 0x7D4954U, 0x7D51BEU, 0x7D606AU, 0x7D7880U, 0x7D8E04U, 0x7D96EEU, + 0x7DA73AU, 0x7DBFD0U, 0x7DC492U, 0x7DDC78U, 0x7DEDACU, 0x7DF546U, 0x7E0668U, 0x7E1E82U, 0x7E2F56U, 0x7E37BCU, + 0x7E4CFEU, 0x7E5414U, 0x7E65C0U, 0x7E7D2AU, 0x7E8BAEU, 0x7E9344U, 0x7EA290U, 0x7EBA7AU, 0x7EC138U, 0x7ED9D2U, + 0x7EE806U, 0x7EF0ECU, 0x7F050EU, 0x7F1DE4U, 0x7F2C30U, 0x7F34DAU, 0x7F4F98U, 0x7F5772U, 0x7F66A6U, 0x7F7E4CU, + 0x7F88C8U, 0x7F9022U, 0x7FA1F6U, 0x7FB91CU, 0x7FC25EU, 0x7FDAB4U, 0x7FEB60U, 0x7FF38AU, 0x800C74U, 0x80149EU, + 0x80254AU, 0x803DA0U, 0x8046E2U, 0x805E08U, 0x806FDCU, 0x807736U, 0x8081B2U, 0x809958U, 0x80A88CU, 0x80B066U, + 0x80CB24U, 0x80D3CEU, 0x80E21AU, 0x80FAF0U, 0x810F12U, 0x8117F8U, 0x81262CU, 0x813EC6U, 0x814584U, 0x815D6EU, + 0x816CBAU, 0x817450U, 0x8182D4U, 0x819A3EU, 0x81ABEAU, 0x81B300U, 0x81C842U, 0x81D0A8U, 0x81E17CU, 0x81F996U, + 0x820AB8U, 0x821252U, 0x822386U, 0x823B6CU, 0x82402EU, 0x8258C4U, 0x826910U, 0x8271FAU, 0x82877EU, 0x829F94U, + 0x82AE40U, 0x82B6AAU, 0x82CDE8U, 0x82D502U, 0x82E4D6U, 0x82FC3CU, 0x8309DEU, 0x831134U, 0x8320E0U, 0x83380AU, + 0x834348U, 0x835BA2U, 0x836A76U, 0x83729CU, 0x838418U, 0x839CF2U, 0x83AD26U, 0x83B5CCU, 0x83CE8EU, 0x83D664U, + 0x83E7B0U, 0x83FF5AU, 0x8401ECU, 0x841906U, 0x8428D2U, 0x843038U, 0x844B7AU, 0x845390U, 0x846244U, 0x847AAEU, + 0x848C2AU, 0x8494C0U, 0x84A514U, 0x84BDFEU, 0x84C6BCU, 0x84DE56U, 0x84EF82U, 0x84F768U, 0x85028AU, 0x851A60U, + 0x852BB4U, 0x85335EU, 0x85481CU, 0x8550F6U, 0x856122U, 0x8579C8U, 0x858F4CU, 0x8597A6U, 0x85A672U, 0x85BE98U, + 0x85C5DAU, 0x85DD30U, 0x85ECE4U, 0x85F40EU, 0x860720U, 0x861FCAU, 0x862E1EU, 0x8636F4U, 0x864DB6U, 0x86555CU, + 0x866488U, 0x867C62U, 0x868AE6U, 0x86920CU, 0x86A3D8U, 0x86BB32U, 0x86C070U, 0x86D89AU, 0x86E94EU, 0x86F1A4U, + 0x870446U, 0x871CACU, 0x872D78U, 0x873592U, 0x874ED0U, 0x87563AU, 0x8767EEU, 0x877F04U, 0x878980U, 0x87916AU, + 0x87A0BEU, 0x87B854U, 0x87C316U, 0x87DBFCU, 0x87EA28U, 0x87F2C2U, 0x880FAEU, 0x881744U, 0x882690U, 0x883E7AU, + 0x884538U, 0x885DD2U, 0x886C06U, 0x8874ECU, 0x888268U, 0x889A82U, 0x88AB56U, 0x88B3BCU, 0x88C8FEU, 0x88D014U, + 0x88E1C0U, 0x88F92AU, 0x890CC8U, 0x891422U, 0x8925F6U, 0x893D1CU, 0x89465EU, 0x895EB4U, 0x896F60U, 0x89778AU, + 0x89810EU, 0x8999E4U, 0x89A830U, 0x89B0DAU, 0x89CB98U, 0x89D372U, 0x89E2A6U, 0x89FA4CU, 0x8A0962U, 0x8A1188U, + 0x8A205CU, 0x8A38B6U, 0x8A43F4U, 0x8A5B1EU, 0x8A6ACAU, 0x8A7220U, 0x8A84A4U, 0x8A9C4EU, 0x8AAD9AU, 0x8AB570U, + 0x8ACE32U, 0x8AD6D8U, 0x8AE70CU, 0x8AFFE6U, 0x8B0A04U, 0x8B12EEU, 0x8B233AU, 0x8B3BD0U, 0x8B4092U, 0x8B5878U, + 0x8B69ACU, 0x8B7146U, 0x8B87C2U, 0x8B9F28U, 0x8BAEFCU, 0x8BB616U, 0x8BCD54U, 0x8BD5BEU, 0x8BE46AU, 0x8BFC80U, + 0x8C0236U, 0x8C1ADCU, 0x8C2B08U, 0x8C33E2U, 0x8C48A0U, 0x8C504AU, 0x8C619EU, 0x8C7974U, 0x8C8FF0U, 0x8C971AU, + 0x8CA6CEU, 0x8CBE24U, 0x8CC566U, 0x8CDD8CU, 0x8CEC58U, 0x8CF4B2U, 0x8D0150U, 0x8D19BAU, 0x8D286EU, 0x8D3084U, + 0x8D4BC6U, 0x8D532CU, 0x8D62F8U, 0x8D7A12U, 0x8D8C96U, 0x8D947CU, 0x8DA5A8U, 0x8DBD42U, 0x8DC600U, 0x8DDEEAU, + 0x8DEF3EU, 0x8DF7D4U, 0x8E04FAU, 0x8E1C10U, 0x8E2DC4U, 0x8E352EU, 0x8E4E6CU, 0x8E5686U, 0x8E6752U, 0x8E7FB8U, + 0x8E893CU, 0x8E91D6U, 0x8EA002U, 0x8EB8E8U, 0x8EC3AAU, 0x8EDB40U, 0x8EEA94U, 0x8EF27EU, 0x8F079CU, 0x8F1F76U, + 0x8F2EA2U, 0x8F3648U, 0x8F4D0AU, 0x8F55E0U, 0x8F6434U, 0x8F7CDEU, 0x8F8A5AU, 0x8F92B0U, 0x8FA364U, 0x8FBB8EU, + 0x8FC0CCU, 0x8FD826U, 0x8FE9F2U, 0x8FF118U, 0x900BC0U, 0x90132AU, 0x9022FEU, 0x903A14U, 0x904156U, 0x9059BCU, + 0x906868U, 0x907082U, 0x908606U, 0x909EECU, 0x90AF38U, 0x90B7D2U, 0x90CC90U, 0x90D47AU, 0x90E5AEU, 0x90FD44U, + 0x9108A6U, 0x91104CU, 0x912198U, 0x913972U, 0x914230U, 0x915ADAU, 0x916B0EU, 0x9173E4U, 0x918560U, 0x919D8AU, + 0x91AC5EU, 0x91B4B4U, 0x91CFF6U, 0x91D71CU, 0x91E6C8U, 0x91FE22U, 0x920D0CU, 0x9215E6U, 0x922432U, 0x923CD8U, + 0x92479AU, 0x925F70U, 0x926EA4U, 0x92764EU, 0x9280CAU, 0x929820U, 0x92A9F4U, 0x92B11EU, 0x92CA5CU, 0x92D2B6U, + 0x92E362U, 0x92FB88U, 0x930E6AU, 0x931680U, 0x932754U, 0x933FBEU, 0x9344FCU, 0x935C16U, 0x936DC2U, 0x937528U, + 0x9383ACU, 0x939B46U, 0x93AA92U, 0x93B278U, 0x93C93AU, 0x93D1D0U, 0x93E004U, 0x93F8EEU, 0x940658U, 0x941EB2U, + 0x942F66U, 0x94378CU, 0x944CCEU, 0x945424U, 0x9465F0U, 0x947D1AU, 0x948B9EU, 0x949374U, 0x94A2A0U, 0x94BA4AU, + 0x94C108U, 0x94D9E2U, 0x94E836U, 0x94F0DCU, 0x95053EU, 0x951DD4U, 0x952C00U, 0x9534EAU, 0x954FA8U, 0x955742U, + 0x956696U, 0x957E7CU, 0x9588F8U, 0x959012U, 0x95A1C6U, 0x95B92CU, 0x95C26EU, 0x95DA84U, 0x95EB50U, 0x95F3BAU, + 0x960094U, 0x96187EU, 0x9629AAU, 0x963140U, 0x964A02U, 0x9652E8U, 0x96633CU, 0x967BD6U, 0x968D52U, 0x9695B8U, + 0x96A46CU, 0x96BC86U, 0x96C7C4U, 0x96DF2EU, 0x96EEFAU, 0x96F610U, 0x9703F2U, 0x971B18U, 0x972ACCU, 0x973226U, + 0x974964U, 0x97518EU, 0x97605AU, 0x9778B0U, 0x978E34U, 0x9796DEU, 0x97A70AU, 0x97BFE0U, 0x97C4A2U, 0x97DC48U, + 0x97ED9CU, 0x97F576U, 0x98081AU, 0x9810F0U, 0x982124U, 0x9839CEU, 0x98428CU, 0x985A66U, 0x986BB2U, 0x987358U, + 0x9885DCU, 0x989D36U, 0x98ACE2U, 0x98B408U, 0x98CF4AU, 0x98D7A0U, 0x98E674U, 0x98FE9EU, 0x990B7CU, 0x991396U, + 0x992242U, 0x993AA8U, 0x9941EAU, 0x995900U, 0x9968D4U, 0x99703EU, 0x9986BAU, 0x999E50U, 0x99AF84U, 0x99B76EU, + 0x99CC2CU, 0x99D4C6U, 0x99E512U, 0x99FDF8U, 0x9A0ED6U, 0x9A163CU, 0x9A27E8U, 0x9A3F02U, 0x9A4440U, 0x9A5CAAU, + 0x9A6D7EU, 0x9A7594U, 0x9A8310U, 0x9A9BFAU, 0x9AAA2EU, 0x9AB2C4U, 0x9AC986U, 0x9AD16CU, 0x9AE0B8U, 0x9AF852U, + 0x9B0DB0U, 0x9B155AU, 0x9B248EU, 0x9B3C64U, 0x9B4726U, 0x9B5FCCU, 0x9B6E18U, 0x9B76F2U, 0x9B8076U, 0x9B989CU, + 0x9BA948U, 0x9BB1A2U, 0x9BCAE0U, 0x9BD20AU, 0x9BE3DEU, 0x9BFB34U, 0x9C0582U, 0x9C1D68U, 0x9C2CBCU, 0x9C3456U, + 0x9C4F14U, 0x9C57FEU, 0x9C662AU, 0x9C7EC0U, 0x9C8844U, 0x9C90AEU, 0x9CA17AU, 0x9CB990U, 0x9CC2D2U, 0x9CDA38U, + 0x9CEBECU, 0x9CF306U, 0x9D06E4U, 0x9D1E0EU, 0x9D2FDAU, 0x9D3730U, 0x9D4C72U, 0x9D5498U, 0x9D654CU, 0x9D7DA6U, + 0x9D8B22U, 0x9D93C8U, 0x9DA21CU, 0x9DBAF6U, 0x9DC1B4U, 0x9DD95EU, 0x9DE88AU, 0x9DF060U, 0x9E034EU, 0x9E1BA4U, + 0x9E2A70U, 0x9E329AU, 0x9E49D8U, 0x9E5132U, 0x9E60E6U, 0x9E780CU, 0x9E8E88U, 0x9E9662U, 0x9EA7B6U, 0x9EBF5CU, + 0x9EC41EU, 0x9EDCF4U, 0x9EED20U, 0x9EF5CAU, 0x9F0028U, 0x9F18C2U, 0x9F2916U, 0x9F31FCU, 0x9F4ABEU, 0x9F5254U, + 0x9F6380U, 0x9F7B6AU, 0x9F8DEEU, 0x9F9504U, 0x9FA4D0U, 0x9FBC3AU, 0x9FC778U, 0x9FDF92U, 0x9FEE46U, 0x9FF6ACU, + 0xA0031CU, 0xA01BF6U, 0xA02A22U, 0xA032C8U, 0xA0498AU, 0xA05160U, 0xA060B4U, 0xA0785EU, 0xA08EDAU, 0xA09630U, + 0xA0A7E4U, 0xA0BF0EU, 0xA0C44CU, 0xA0DCA6U, 0xA0ED72U, 0xA0F598U, 0xA1007AU, 0xA11890U, 0xA12944U, 0xA131AEU, + 0xA14AECU, 0xA15206U, 0xA163D2U, 0xA17B38U, 0xA18DBCU, 0xA19556U, 0xA1A482U, 0xA1BC68U, 0xA1C72AU, 0xA1DFC0U, + 0xA1EE14U, 0xA1F6FEU, 0xA205D0U, 0xA21D3AU, 0xA22CEEU, 0xA23404U, 0xA24F46U, 0xA257ACU, 0xA26678U, 0xA27E92U, + 0xA28816U, 0xA290FCU, 0xA2A128U, 0xA2B9C2U, 0xA2C280U, 0xA2DA6AU, 0xA2EBBEU, 0xA2F354U, 0xA306B6U, 0xA31E5CU, + 0xA32F88U, 0xA33762U, 0xA34C20U, 0xA354CAU, 0xA3651EU, 0xA37DF4U, 0xA38B70U, 0xA3939AU, 0xA3A24EU, 0xA3BAA4U, + 0xA3C1E6U, 0xA3D90CU, 0xA3E8D8U, 0xA3F032U, 0xA40E84U, 0xA4166EU, 0xA427BAU, 0xA43F50U, 0xA44412U, 0xA45CF8U, + 0xA46D2CU, 0xA475C6U, 0xA48342U, 0xA49BA8U, 0xA4AA7CU, 0xA4B296U, 0xA4C9D4U, 0xA4D13EU, 0xA4E0EAU, 0xA4F800U, + 0xA50DE2U, 0xA51508U, 0xA524DCU, 0xA53C36U, 0xA54774U, 0xA55F9EU, 0xA56E4AU, 0xA576A0U, 0xA58024U, 0xA598CEU, + 0xA5A91AU, 0xA5B1F0U, 0xA5CAB2U, 0xA5D258U, 0xA5E38CU, 0xA5FB66U, 0xA60848U, 0xA610A2U, 0xA62176U, 0xA6399CU, + 0xA642DEU, 0xA65A34U, 0xA66BE0U, 0xA6730AU, 0xA6858EU, 0xA69D64U, 0xA6ACB0U, 0xA6B45AU, 0xA6CF18U, 0xA6D7F2U, + 0xA6E626U, 0xA6FECCU, 0xA70B2EU, 0xA713C4U, 0xA72210U, 0xA73AFAU, 0xA741B8U, 0xA75952U, 0xA76886U, 0xA7706CU, + 0xA786E8U, 0xA79E02U, 0xA7AFD6U, 0xA7B73CU, 0xA7CC7EU, 0xA7D494U, 0xA7E540U, 0xA7FDAAU, 0xA800C6U, 0xA8182CU, + 0xA829F8U, 0xA83112U, 0xA84A50U, 0xA852BAU, 0xA8636EU, 0xA87B84U, 0xA88D00U, 0xA895EAU, 0xA8A43EU, 0xA8BCD4U, + 0xA8C796U, 0xA8DF7CU, 0xA8EEA8U, 0xA8F642U, 0xA903A0U, 0xA91B4AU, 0xA92A9EU, 0xA93274U, 0xA94936U, 0xA951DCU, + 0xA96008U, 0xA978E2U, 0xA98E66U, 0xA9968CU, 0xA9A758U, 0xA9BFB2U, 0xA9C4F0U, 0xA9DC1AU, 0xA9EDCEU, 0xA9F524U, + 0xAA060AU, 0xAA1EE0U, 0xAA2F34U, 0xAA37DEU, 0xAA4C9CU, 0xAA5476U, 0xAA65A2U, 0xAA7D48U, 0xAA8BCCU, 0xAA9326U, + 0xAAA2F2U, 0xAABA18U, 0xAAC15AU, 0xAAD9B0U, 0xAAE864U, 0xAAF08EU, 0xAB056CU, 0xAB1D86U, 0xAB2C52U, 0xAB34B8U, + 0xAB4FFAU, 0xAB5710U, 0xAB66C4U, 0xAB7E2EU, 0xAB88AAU, 0xAB9040U, 0xABA194U, 0xABB97EU, 0xABC23CU, 0xABDAD6U, + 0xABEB02U, 0xABF3E8U, 0xAC0D5EU, 0xAC15B4U, 0xAC2460U, 0xAC3C8AU, 0xAC47C8U, 0xAC5F22U, 0xAC6EF6U, 0xAC761CU, + 0xAC8098U, 0xAC9872U, 0xACA9A6U, 0xACB14CU, 0xACCA0EU, 0xACD2E4U, 0xACE330U, 0xACFBDAU, 0xAD0E38U, 0xAD16D2U, + 0xAD2706U, 0xAD3FECU, 0xAD44AEU, 0xAD5C44U, 0xAD6D90U, 0xAD757AU, 0xAD83FEU, 0xAD9B14U, 0xADAAC0U, 0xADB22AU, + 0xADC968U, 0xADD182U, 0xADE056U, 0xADF8BCU, 0xAE0B92U, 0xAE1378U, 0xAE22ACU, 0xAE3A46U, 0xAE4104U, 0xAE59EEU, + 0xAE683AU, 0xAE70D0U, 0xAE8654U, 0xAE9EBEU, 0xAEAF6AU, 0xAEB780U, 0xAECCC2U, 0xAED428U, 0xAEE5FCU, 0xAEFD16U, + 0xAF08F4U, 0xAF101EU, 0xAF21CAU, 0xAF3920U, 0xAF4262U, 0xAF5A88U, 0xAF6B5CU, 0xAF73B6U, 0xAF8532U, 0xAF9DD8U, + 0xAFAC0CU, 0xAFB4E6U, 0xAFCFA4U, 0xAFD74EU, 0xAFE69AU, 0xAFFE70U, 0xB004A8U, 0xB01C42U, 0xB02D96U, 0xB0357CU, + 0xB04E3EU, 0xB056D4U, 0xB06700U, 0xB07FEAU, 0xB0896EU, 0xB09184U, 0xB0A050U, 0xB0B8BAU, 0xB0C3F8U, 0xB0DB12U, + 0xB0EAC6U, 0xB0F22CU, 0xB107CEU, 0xB11F24U, 0xB12EF0U, 0xB1361AU, 0xB14D58U, 0xB155B2U, 0xB16466U, 0xB17C8CU, + 0xB18A08U, 0xB192E2U, 0xB1A336U, 0xB1BBDCU, 0xB1C09EU, 0xB1D874U, 0xB1E9A0U, 0xB1F14AU, 0xB20264U, 0xB21A8EU, + 0xB22B5AU, 0xB233B0U, 0xB248F2U, 0xB25018U, 0xB261CCU, 0xB27926U, 0xB28FA2U, 0xB29748U, 0xB2A69CU, 0xB2BE76U, + 0xB2C534U, 0xB2DDDEU, 0xB2EC0AU, 0xB2F4E0U, 0xB30102U, 0xB319E8U, 0xB3283CU, 0xB330D6U, 0xB34B94U, 0xB3537EU, + 0xB362AAU, 0xB37A40U, 0xB38CC4U, 0xB3942EU, 0xB3A5FAU, 0xB3BD10U, 0xB3C652U, 0xB3DEB8U, 0xB3EF6CU, 0xB3F786U, + 0xB40930U, 0xB411DAU, 0xB4200EU, 0xB438E4U, 0xB443A6U, 0xB45B4CU, 0xB46A98U, 0xB47272U, 0xB484F6U, 0xB49C1CU, + 0xB4ADC8U, 0xB4B522U, 0xB4CE60U, 0xB4D68AU, 0xB4E75EU, 0xB4FFB4U, 0xB50A56U, 0xB512BCU, 0xB52368U, 0xB53B82U, + 0xB540C0U, 0xB5582AU, 0xB569FEU, 0xB57114U, 0xB58790U, 0xB59F7AU, 0xB5AEAEU, 0xB5B644U, 0xB5CD06U, 0xB5D5ECU, + 0xB5E438U, 0xB5FCD2U, 0xB60FFCU, 0xB61716U, 0xB626C2U, 0xB63E28U, 0xB6456AU, 0xB65D80U, 0xB66C54U, 0xB674BEU, + 0xB6823AU, 0xB69AD0U, 0xB6AB04U, 0xB6B3EEU, 0xB6C8ACU, 0xB6D046U, 0xB6E192U, 0xB6F978U, 0xB70C9AU, 0xB71470U, + 0xB725A4U, 0xB73D4EU, 0xB7460CU, 0xB75EE6U, 0xB76F32U, 0xB777D8U, 0xB7815CU, 0xB799B6U, 0xB7A862U, 0xB7B088U, + 0xB7CBCAU, 0xB7D320U, 0xB7E2F4U, 0xB7FA1EU, 0xB80772U, 0xB81F98U, 0xB82E4CU, 0xB836A6U, 0xB84DE4U, 0xB8550EU, + 0xB864DAU, 0xB87C30U, 0xB88AB4U, 0xB8925EU, 0xB8A38AU, 0xB8BB60U, 0xB8C022U, 0xB8D8C8U, 0xB8E91CU, 0xB8F1F6U, + 0xB90414U, 0xB91CFEU, 0xB92D2AU, 0xB935C0U, 0xB94E82U, 0xB95668U, 0xB967BCU, 0xB97F56U, 0xB989D2U, 0xB99138U, + 0xB9A0ECU, 0xB9B806U, 0xB9C344U, 0xB9DBAEU, 0xB9EA7AU, 0xB9F290U, 0xBA01BEU, 0xBA1954U, 0xBA2880U, 0xBA306AU, + 0xBA4B28U, 0xBA53C2U, 0xBA6216U, 0xBA7AFCU, 0xBA8C78U, 0xBA9492U, 0xBAA546U, 0xBABDACU, 0xBAC6EEU, 0xBADE04U, + 0xBAEFD0U, 0xBAF73AU, 0xBB02D8U, 0xBB1A32U, 0xBB2BE6U, 0xBB330CU, 0xBB484EU, 0xBB50A4U, 0xBB6170U, 0xBB799AU, + 0xBB8F1EU, 0xBB97F4U, 0xBBA620U, 0xBBBECAU, 0xBBC588U, 0xBBDD62U, 0xBBECB6U, 0xBBF45CU, 0xBC0AEAU, 0xBC1200U, + 0xBC23D4U, 0xBC3B3EU, 0xBC407CU, 0xBC5896U, 0xBC6942U, 0xBC71A8U, 0xBC872CU, 0xBC9FC6U, 0xBCAE12U, 0xBCB6F8U, + 0xBCCDBAU, 0xBCD550U, 0xBCE484U, 0xBCFC6EU, 0xBD098CU, 0xBD1166U, 0xBD20B2U, 0xBD3858U, 0xBD431AU, 0xBD5BF0U, + 0xBD6A24U, 0xBD72CEU, 0xBD844AU, 0xBD9CA0U, 0xBDAD74U, 0xBDB59EU, 0xBDCEDCU, 0xBDD636U, 0xBDE7E2U, 0xBDFF08U, + 0xBE0C26U, 0xBE14CCU, 0xBE2518U, 0xBE3DF2U, 0xBE46B0U, 0xBE5E5AU, 0xBE6F8EU, 0xBE7764U, 0xBE81E0U, 0xBE990AU, + 0xBEA8DEU, 0xBEB034U, 0xBECB76U, 0xBED39CU, 0xBEE248U, 0xBEFAA2U, 0xBF0F40U, 0xBF17AAU, 0xBF267EU, 0xBF3E94U, + 0xBF45D6U, 0xBF5D3CU, 0xBF6CE8U, 0xBF7402U, 0xBF8286U, 0xBF9A6CU, 0xBFABB8U, 0xBFB352U, 0xBFC810U, 0xBFD0FAU, + 0xBFE12EU, 0xBFF9C4U, 0xC00A4EU, 0xC012A4U, 0xC02370U, 0xC03B9AU, 0xC040D8U, 0xC05832U, 0xC069E6U, 0xC0710CU, + 0xC08788U, 0xC09F62U, 0xC0AEB6U, 0xC0B65CU, 0xC0CD1EU, 0xC0D5F4U, 0xC0E420U, 0xC0FCCAU, 0xC10928U, 0xC111C2U, + 0xC12016U, 0xC138FCU, 0xC143BEU, 0xC15B54U, 0xC16A80U, 0xC1726AU, 0xC184EEU, 0xC19C04U, 0xC1ADD0U, 0xC1B53AU, + 0xC1CE78U, 0xC1D692U, 0xC1E746U, 0xC1FFACU, 0xC20C82U, 0xC21468U, 0xC225BCU, 0xC23D56U, 0xC24614U, 0xC25EFEU, + 0xC26F2AU, 0xC277C0U, 0xC28144U, 0xC299AEU, 0xC2A87AU, 0xC2B090U, 0xC2CBD2U, 0xC2D338U, 0xC2E2ECU, 0xC2FA06U, + 0xC30FE4U, 0xC3170EU, 0xC326DAU, 0xC33E30U, 0xC34572U, 0xC35D98U, 0xC36C4CU, 0xC374A6U, 0xC38222U, 0xC39AC8U, + 0xC3AB1CU, 0xC3B3F6U, 0xC3C8B4U, 0xC3D05EU, 0xC3E18AU, 0xC3F960U, 0xC407D6U, 0xC41F3CU, 0xC42EE8U, 0xC43602U, + 0xC44D40U, 0xC455AAU, 0xC4647EU, 0xC47C94U, 0xC48A10U, 0xC492FAU, 0xC4A32EU, 0xC4BBC4U, 0xC4C086U, 0xC4D86CU, + 0xC4E9B8U, 0xC4F152U, 0xC504B0U, 0xC51C5AU, 0xC52D8EU, 0xC53564U, 0xC54E26U, 0xC556CCU, 0xC56718U, 0xC57FF2U, + 0xC58976U, 0xC5919CU, 0xC5A048U, 0xC5B8A2U, 0xC5C3E0U, 0xC5DB0AU, 0xC5EADEU, 0xC5F234U, 0xC6011AU, 0xC619F0U, + 0xC62824U, 0xC630CEU, 0xC64B8CU, 0xC65366U, 0xC662B2U, 0xC67A58U, 0xC68CDCU, 0xC69436U, 0xC6A5E2U, 0xC6BD08U, + 0xC6C64AU, 0xC6DEA0U, 0xC6EF74U, 0xC6F79EU, 0xC7027CU, 0xC71A96U, 0xC72B42U, 0xC733A8U, 0xC748EAU, 0xC75000U, + 0xC761D4U, 0xC7793EU, 0xC78FBAU, 0xC79750U, 0xC7A684U, 0xC7BE6EU, 0xC7C52CU, 0xC7DDC6U, 0xC7EC12U, 0xC7F4F8U, + 0xC80994U, 0xC8117EU, 0xC820AAU, 0xC83840U, 0xC84302U, 0xC85BE8U, 0xC86A3CU, 0xC872D6U, 0xC88452U, 0xC89CB8U, + 0xC8AD6CU, 0xC8B586U, 0xC8CEC4U, 0xC8D62EU, 0xC8E7FAU, 0xC8FF10U, 0xC90AF2U, 0xC91218U, 0xC923CCU, 0xC93B26U, + 0xC94064U, 0xC9588EU, 0xC9695AU, 0xC971B0U, 0xC98734U, 0xC99FDEU, 0xC9AE0AU, 0xC9B6E0U, 0xC9CDA2U, 0xC9D548U, + 0xC9E49CU, 0xC9FC76U, 0xCA0F58U, 0xCA17B2U, 0xCA2666U, 0xCA3E8CU, 0xCA45CEU, 0xCA5D24U, 0xCA6CF0U, 0xCA741AU, + 0xCA829EU, 0xCA9A74U, 0xCAABA0U, 0xCAB34AU, 0xCAC808U, 0xCAD0E2U, 0xCAE136U, 0xCAF9DCU, 0xCB0C3EU, 0xCB14D4U, + 0xCB2500U, 0xCB3DEAU, 0xCB46A8U, 0xCB5E42U, 0xCB6F96U, 0xCB777CU, 0xCB81F8U, 0xCB9912U, 0xCBA8C6U, 0xCBB02CU, + 0xCBCB6EU, 0xCBD384U, 0xCBE250U, 0xCBFABAU, 0xCC040CU, 0xCC1CE6U, 0xCC2D32U, 0xCC35D8U, 0xCC4E9AU, 0xCC5670U, + 0xCC67A4U, 0xCC7F4EU, 0xCC89CAU, 0xCC9120U, 0xCCA0F4U, 0xCCB81EU, 0xCCC35CU, 0xCCDBB6U, 0xCCEA62U, 0xCCF288U, + 0xCD076AU, 0xCD1F80U, 0xCD2E54U, 0xCD36BEU, 0xCD4DFCU, 0xCD5516U, 0xCD64C2U, 0xCD7C28U, 0xCD8AACU, 0xCD9246U, + 0xCDA392U, 0xCDBB78U, 0xCDC03AU, 0xCDD8D0U, 0xCDE904U, 0xCDF1EEU, 0xCE02C0U, 0xCE1A2AU, 0xCE2BFEU, 0xCE3314U, + 0xCE4856U, 0xCE50BCU, 0xCE6168U, 0xCE7982U, 0xCE8F06U, 0xCE97ECU, 0xCEA638U, 0xCEBED2U, 0xCEC590U, 0xCEDD7AU, + 0xCEECAEU, 0xCEF444U, 0xCF01A6U, 0xCF194CU, 0xCF2898U, 0xCF3072U, 0xCF4B30U, 0xCF53DAU, 0xCF620EU, 0xCF7AE4U, + 0xCF8C60U, 0xCF948AU, 0xCFA55EU, 0xCFBDB4U, 0xCFC6F6U, 0xCFDE1CU, 0xCFEFC8U, 0xCFF722U, 0xD00DFAU, 0xD01510U, + 0xD024C4U, 0xD03C2EU, 0xD0476CU, 0xD05F86U, 0xD06E52U, 0xD076B8U, 0xD0803CU, 0xD098D6U, 0xD0A902U, 0xD0B1E8U, + 0xD0CAAAU, 0xD0D240U, 0xD0E394U, 0xD0FB7EU, 0xD10E9CU, 0xD11676U, 0xD127A2U, 0xD13F48U, 0xD1440AU, 0xD15CE0U, + 0xD16D34U, 0xD175DEU, 0xD1835AU, 0xD19BB0U, 0xD1AA64U, 0xD1B28EU, 0xD1C9CCU, 0xD1D126U, 0xD1E0F2U, 0xD1F818U, + 0xD20B36U, 0xD213DCU, 0xD22208U, 0xD23AE2U, 0xD241A0U, 0xD2594AU, 0xD2689EU, 0xD27074U, 0xD286F0U, 0xD29E1AU, + 0xD2AFCEU, 0xD2B724U, 0xD2CC66U, 0xD2D48CU, 0xD2E558U, 0xD2FDB2U, 0xD30850U, 0xD310BAU, 0xD3216EU, 0xD33984U, + 0xD342C6U, 0xD35A2CU, 0xD36BF8U, 0xD37312U, 0xD38596U, 0xD39D7CU, 0xD3ACA8U, 0xD3B442U, 0xD3CF00U, 0xD3D7EAU, + 0xD3E63EU, 0xD3FED4U, 0xD40062U, 0xD41888U, 0xD4295CU, 0xD431B6U, 0xD44AF4U, 0xD4521EU, 0xD463CAU, 0xD47B20U, + 0xD48DA4U, 0xD4954EU, 0xD4A49AU, 0xD4BC70U, 0xD4C732U, 0xD4DFD8U, 0xD4EE0CU, 0xD4F6E6U, 0xD50304U, 0xD51BEEU, + 0xD52A3AU, 0xD532D0U, 0xD54992U, 0xD55178U, 0xD560ACU, 0xD57846U, 0xD58EC2U, 0xD59628U, 0xD5A7FCU, 0xD5BF16U, + 0xD5C454U, 0xD5DCBEU, 0xD5ED6AU, 0xD5F580U, 0xD606AEU, 0xD61E44U, 0xD62F90U, 0xD6377AU, 0xD64C38U, 0xD654D2U, + 0xD66506U, 0xD67DECU, 0xD68B68U, 0xD69382U, 0xD6A256U, 0xD6BABCU, 0xD6C1FEU, 0xD6D914U, 0xD6E8C0U, 0xD6F02AU, + 0xD705C8U, 0xD71D22U, 0xD72CF6U, 0xD7341CU, 0xD74F5EU, 0xD757B4U, 0xD76660U, 0xD77E8AU, 0xD7880EU, 0xD790E4U, + 0xD7A130U, 0xD7B9DAU, 0xD7C298U, 0xD7DA72U, 0xD7EBA6U, 0xD7F34CU, 0xD80E20U, 0xD816CAU, 0xD8271EU, 0xD83FF4U, + 0xD844B6U, 0xD85C5CU, 0xD86D88U, 0xD87562U, 0xD883E6U, 0xD89B0CU, 0xD8AAD8U, 0xD8B232U, 0xD8C970U, 0xD8D19AU, + 0xD8E04EU, 0xD8F8A4U, 0xD90D46U, 0xD915ACU, 0xD92478U, 0xD93C92U, 0xD947D0U, 0xD95F3AU, 0xD96EEEU, 0xD97604U, + 0xD98080U, 0xD9986AU, 0xD9A9BEU, 0xD9B154U, 0xD9CA16U, 0xD9D2FCU, 0xD9E328U, 0xD9FBC2U, 0xDA08ECU, 0xDA1006U, + 0xDA21D2U, 0xDA3938U, 0xDA427AU, 0xDA5A90U, 0xDA6B44U, 0xDA73AEU, 0xDA852AU, 0xDA9DC0U, 0xDAAC14U, 0xDAB4FEU, + 0xDACFBCU, 0xDAD756U, 0xDAE682U, 0xDAFE68U, 0xDB0B8AU, 0xDB1360U, 0xDB22B4U, 0xDB3A5EU, 0xDB411CU, 0xDB59F6U, + 0xDB6822U, 0xDB70C8U, 0xDB864CU, 0xDB9EA6U, 0xDBAF72U, 0xDBB798U, 0xDBCCDAU, 0xDBD430U, 0xDBE5E4U, 0xDBFD0EU, + 0xDC03B8U, 0xDC1B52U, 0xDC2A86U, 0xDC326CU, 0xDC492EU, 0xDC51C4U, 0xDC6010U, 0xDC78FAU, 0xDC8E7EU, 0xDC9694U, + 0xDCA740U, 0xDCBFAAU, 0xDCC4E8U, 0xDCDC02U, 0xDCEDD6U, 0xDCF53CU, 0xDD00DEU, 0xDD1834U, 0xDD29E0U, 0xDD310AU, + 0xDD4A48U, 0xDD52A2U, 0xDD6376U, 0xDD7B9CU, 0xDD8D18U, 0xDD95F2U, 0xDDA426U, 0xDDBCCCU, 0xDDC78EU, 0xDDDF64U, + 0xDDEEB0U, 0xDDF65AU, 0xDE0574U, 0xDE1D9EU, 0xDE2C4AU, 0xDE34A0U, 0xDE4FE2U, 0xDE5708U, 0xDE66DCU, 0xDE7E36U, + 0xDE88B2U, 0xDE9058U, 0xDEA18CU, 0xDEB966U, 0xDEC224U, 0xDEDACEU, 0xDEEB1AU, 0xDEF3F0U, 0xDF0612U, 0xDF1EF8U, + 0xDF2F2CU, 0xDF37C6U, 0xDF4C84U, 0xDF546EU, 0xDF65BAU, 0xDF7D50U, 0xDF8BD4U, 0xDF933EU, 0xDFA2EAU, 0xDFBA00U, + 0xDFC142U, 0xDFD9A8U, 0xDFE87CU, 0xDFF096U, 0xE00526U, 0xE01DCCU, 0xE02C18U, 0xE034F2U, 0xE04FB0U, 0xE0575AU, + 0xE0668EU, 0xE07E64U, 0xE088E0U, 0xE0900AU, 0xE0A1DEU, 0xE0B934U, 0xE0C276U, 0xE0DA9CU, 0xE0EB48U, 0xE0F3A2U, + 0xE10640U, 0xE11EAAU, 0xE12F7EU, 0xE13794U, 0xE14CD6U, 0xE1543CU, 0xE165E8U, 0xE17D02U, 0xE18B86U, 0xE1936CU, + 0xE1A2B8U, 0xE1BA52U, 0xE1C110U, 0xE1D9FAU, 0xE1E82EU, 0xE1F0C4U, 0xE203EAU, 0xE21B00U, 0xE22AD4U, 0xE2323EU, + 0xE2497CU, 0xE25196U, 0xE26042U, 0xE278A8U, 0xE28E2CU, 0xE296C6U, 0xE2A712U, 0xE2BFF8U, 0xE2C4BAU, 0xE2DC50U, + 0xE2ED84U, 0xE2F56EU, 0xE3008CU, 0xE31866U, 0xE329B2U, 0xE33158U, 0xE34A1AU, 0xE352F0U, 0xE36324U, 0xE37BCEU, + 0xE38D4AU, 0xE395A0U, 0xE3A474U, 0xE3BC9EU, 0xE3C7DCU, 0xE3DF36U, 0xE3EEE2U, 0xE3F608U, 0xE408BEU, 0xE41054U, + 0xE42180U, 0xE4396AU, 0xE44228U, 0xE45AC2U, 0xE46B16U, 0xE473FCU, 0xE48578U, 0xE49D92U, 0xE4AC46U, 0xE4B4ACU, + 0xE4CFEEU, 0xE4D704U, 0xE4E6D0U, 0xE4FE3AU, 0xE50BD8U, 0xE51332U, 0xE522E6U, 0xE53A0CU, 0xE5414EU, 0xE559A4U, + 0xE56870U, 0xE5709AU, 0xE5861EU, 0xE59EF4U, 0xE5AF20U, 0xE5B7CAU, 0xE5CC88U, 0xE5D462U, 0xE5E5B6U, 0xE5FD5CU, + 0xE60E72U, 0xE61698U, 0xE6274CU, 0xE63FA6U, 0xE644E4U, 0xE65C0EU, 0xE66DDAU, 0xE67530U, 0xE683B4U, 0xE69B5EU, + 0xE6AA8AU, 0xE6B260U, 0xE6C922U, 0xE6D1C8U, 0xE6E01CU, 0xE6F8F6U, 0xE70D14U, 0xE715FEU, 0xE7242AU, 0xE73CC0U, + 0xE74782U, 0xE75F68U, 0xE76EBCU, 0xE77656U, 0xE780D2U, 0xE79838U, 0xE7A9ECU, 0xE7B106U, 0xE7CA44U, 0xE7D2AEU, + 0xE7E37AU, 0xE7FB90U, 0xE806FCU, 0xE81E16U, 0xE82FC2U, 0xE83728U, 0xE84C6AU, 0xE85480U, 0xE86554U, 0xE87DBEU, + 0xE88B3AU, 0xE893D0U, 0xE8A204U, 0xE8BAEEU, 0xE8C1ACU, 0xE8D946U, 0xE8E892U, 0xE8F078U, 0xE9059AU, 0xE91D70U, + 0xE92CA4U, 0xE9344EU, 0xE94F0CU, 0xE957E6U, 0xE96632U, 0xE97ED8U, 0xE9885CU, 0xE990B6U, 0xE9A162U, 0xE9B988U, + 0xE9C2CAU, 0xE9DA20U, 0xE9EBF4U, 0xE9F31EU, 0xEA0030U, 0xEA18DAU, 0xEA290EU, 0xEA31E4U, 0xEA4AA6U, 0xEA524CU, + 0xEA6398U, 0xEA7B72U, 0xEA8DF6U, 0xEA951CU, 0xEAA4C8U, 0xEABC22U, 0xEAC760U, 0xEADF8AU, 0xEAEE5EU, 0xEAF6B4U, + 0xEB0356U, 0xEB1BBCU, 0xEB2A68U, 0xEB3282U, 0xEB49C0U, 0xEB512AU, 0xEB60FEU, 0xEB7814U, 0xEB8E90U, 0xEB967AU, + 0xEBA7AEU, 0xEBBF44U, 0xEBC406U, 0xEBDCECU, 0xEBED38U, 0xEBF5D2U, 0xEC0B64U, 0xEC138EU, 0xEC225AU, 0xEC3AB0U, + 0xEC41F2U, 0xEC5918U, 0xEC68CCU, 0xEC7026U, 0xEC86A2U, 0xEC9E48U, 0xECAF9CU, 0xECB776U, 0xECCC34U, 0xECD4DEU, + 0xECE50AU, 0xECFDE0U, 0xED0802U, 0xED10E8U, 0xED213CU, 0xED39D6U, 0xED4294U, 0xED5A7EU, 0xED6BAAU, 0xED7340U, + 0xED85C4U, 0xED9D2EU, 0xEDACFAU, 0xEDB410U, 0xEDCF52U, 0xEDD7B8U, 0xEDE66CU, 0xEDFE86U, 0xEE0DA8U, 0xEE1542U, + 0xEE2496U, 0xEE3C7CU, 0xEE473EU, 0xEE5FD4U, 0xEE6E00U, 0xEE76EAU, 0xEE806EU, 0xEE9884U, 0xEEA950U, 0xEEB1BAU, + 0xEECAF8U, 0xEED212U, 0xEEE3C6U, 0xEEFB2CU, 0xEF0ECEU, 0xEF1624U, 0xEF27F0U, 0xEF3F1AU, 0xEF4458U, 0xEF5CB2U, + 0xEF6D66U, 0xEF758CU, 0xEF8308U, 0xEF9BE2U, 0xEFAA36U, 0xEFB2DCU, 0xEFC99EU, 0xEFD174U, 0xEFE0A0U, 0xEFF84AU, + 0xF00292U, 0xF01A78U, 0xF02BACU, 0xF03346U, 0xF04804U, 0xF050EEU, 0xF0613AU, 0xF079D0U, 0xF08F54U, 0xF097BEU, + 0xF0A66AU, 0xF0BE80U, 0xF0C5C2U, 0xF0DD28U, 0xF0ECFCU, 0xF0F416U, 0xF101F4U, 0xF1191EU, 0xF128CAU, 0xF13020U, + 0xF14B62U, 0xF15388U, 0xF1625CU, 0xF17AB6U, 0xF18C32U, 0xF194D8U, 0xF1A50CU, 0xF1BDE6U, 0xF1C6A4U, 0xF1DE4EU, + 0xF1EF9AU, 0xF1F770U, 0xF2045EU, 0xF21CB4U, 0xF22D60U, 0xF2358AU, 0xF24EC8U, 0xF25622U, 0xF267F6U, 0xF27F1CU, + 0xF28998U, 0xF29172U, 0xF2A0A6U, 0xF2B84CU, 0xF2C30EU, 0xF2DBE4U, 0xF2EA30U, 0xF2F2DAU, 0xF30738U, 0xF31FD2U, + 0xF32E06U, 0xF336ECU, 0xF34DAEU, 0xF35544U, 0xF36490U, 0xF37C7AU, 0xF38AFEU, 0xF39214U, 0xF3A3C0U, 0xF3BB2AU, + 0xF3C068U, 0xF3D882U, 0xF3E956U, 0xF3F1BCU, 0xF40F0AU, 0xF417E0U, 0xF42634U, 0xF43EDEU, 0xF4459CU, 0xF45D76U, + 0xF46CA2U, 0xF47448U, 0xF482CCU, 0xF49A26U, 0xF4ABF2U, 0xF4B318U, 0xF4C85AU, 0xF4D0B0U, 0xF4E164U, 0xF4F98EU, + 0xF50C6CU, 0xF51486U, 0xF52552U, 0xF53DB8U, 0xF546FAU, 0xF55E10U, 0xF56FC4U, 0xF5772EU, 0xF581AAU, 0xF59940U, + 0xF5A894U, 0xF5B07EU, 0xF5CB3CU, 0xF5D3D6U, 0xF5E202U, 0xF5FAE8U, 0xF609C6U, 0xF6112CU, 0xF620F8U, 0xF63812U, + 0xF64350U, 0xF65BBAU, 0xF66A6EU, 0xF67284U, 0xF68400U, 0xF69CEAU, 0xF6AD3EU, 0xF6B5D4U, 0xF6CE96U, 0xF6D67CU, + 0xF6E7A8U, 0xF6FF42U, 0xF70AA0U, 0xF7124AU, 0xF7239EU, 0xF73B74U, 0xF74036U, 0xF758DCU, 0xF76908U, 0xF771E2U, + 0xF78766U, 0xF79F8CU, 0xF7AE58U, 0xF7B6B2U, 0xF7CDF0U, 0xF7D51AU, 0xF7E4CEU, 0xF7FC24U, 0xF80148U, 0xF819A2U, + 0xF82876U, 0xF8309CU, 0xF84BDEU, 0xF85334U, 0xF862E0U, 0xF87A0AU, 0xF88C8EU, 0xF89464U, 0xF8A5B0U, 0xF8BD5AU, + 0xF8C618U, 0xF8DEF2U, 0xF8EF26U, 0xF8F7CCU, 0xF9022EU, 0xF91AC4U, 0xF92B10U, 0xF933FAU, 0xF948B8U, 0xF95052U, + 0xF96186U, 0xF9796CU, 0xF98FE8U, 0xF99702U, 0xF9A6D6U, 0xF9BE3CU, 0xF9C57EU, 0xF9DD94U, 0xF9EC40U, 0xF9F4AAU, + 0xFA0784U, 0xFA1F6EU, 0xFA2EBAU, 0xFA3650U, 0xFA4D12U, 0xFA55F8U, 0xFA642CU, 0xFA7CC6U, 0xFA8A42U, 0xFA92A8U, + 0xFAA37CU, 0xFABB96U, 0xFAC0D4U, 0xFAD83EU, 0xFAE9EAU, 0xFAF100U, 0xFB04E2U, 0xFB1C08U, 0xFB2DDCU, 0xFB3536U, + 0xFB4E74U, 0xFB569EU, 0xFB674AU, 0xFB7FA0U, 0xFB8924U, 0xFB91CEU, 0xFBA01AU, 0xFBB8F0U, 0xFBC3B2U, 0xFBDB58U, + 0xFBEA8CU, 0xFBF266U, 0xFC0CD0U, 0xFC143AU, 0xFC25EEU, 0xFC3D04U, 0xFC4646U, 0xFC5EACU, 0xFC6F78U, 0xFC7792U, + 0xFC8116U, 0xFC99FCU, 0xFCA828U, 0xFCB0C2U, 0xFCCB80U, 0xFCD36AU, 0xFCE2BEU, 0xFCFA54U, 0xFD0FB6U, 0xFD175CU, + 0xFD2688U, 0xFD3E62U, 0xFD4520U, 0xFD5DCAU, 0xFD6C1EU, 0xFD74F4U, 0xFD8270U, 0xFD9A9AU, 0xFDAB4EU, 0xFDB3A4U, + 0xFDC8E6U, 0xFDD00CU, 0xFDE1D8U, 0xFDF932U, 0xFE0A1CU, 0xFE12F6U, 0xFE2322U, 0xFE3BC8U, 0xFE408AU, 0xFE5860U, + 0xFE69B4U, 0xFE715EU, 0xFE87DAU, 0xFE9F30U, 0xFEAEE4U, 0xFEB60EU, 0xFECD4CU, 0xFED5A6U, 0xFEE472U, 0xFEFC98U, + 0xFF097AU, 0xFF1190U, 0xFF2044U, 0xFF38AEU, 0xFF43ECU, 0xFF5B06U, 0xFF6AD2U, 0xFF7238U, 0xFF84BCU, 0xFF9C56U, + 0xFFAD82U, 0xFFB568U, 0xFFCE2AU, 0xFFD6C0U, 0xFFE714U, 0xFFFFFEU }; + +static const uint32_t ENCODING_TABLE_24128[] = { + 0x000000U, 0x0018EBU, 0x00293EU, 0x0031D5U, 0x004A97U, 0x00527CU, 0x0063A9U, 0x007B42U, 0x008DC6U, 0x00952DU, + 0x00A4F8U, 0x00BC13U, 0x00C751U, 0x00DFBAU, 0x00EE6FU, 0x00F684U, 0x010367U, 0x011B8CU, 0x012A59U, 0x0132B2U, + 0x0149F0U, 0x01511BU, 0x0160CEU, 0x017825U, 0x018EA1U, 0x01964AU, 0x01A79FU, 0x01BF74U, 0x01C436U, 0x01DCDDU, + 0x01ED08U, 0x01F5E3U, 0x0206CDU, 0x021E26U, 0x022FF3U, 0x023718U, 0x024C5AU, 0x0254B1U, 0x026564U, 0x027D8FU, + 0x028B0BU, 0x0293E0U, 0x02A235U, 0x02BADEU, 0x02C19CU, 0x02D977U, 0x02E8A2U, 0x02F049U, 0x0305AAU, 0x031D41U, + 0x032C94U, 0x03347FU, 0x034F3DU, 0x0357D6U, 0x036603U, 0x037EE8U, 0x03886CU, 0x039087U, 0x03A152U, 0x03B9B9U, + 0x03C2FBU, 0x03DA10U, 0x03EBC5U, 0x03F32EU, 0x040D99U, 0x041572U, 0x0424A7U, 0x043C4CU, 0x04470EU, 0x045FE5U, + 0x046E30U, 0x0476DBU, 0x04805FU, 0x0498B4U, 0x04A961U, 0x04B18AU, 0x04CAC8U, 0x04D223U, 0x04E3F6U, 0x04FB1DU, + 0x050EFEU, 0x051615U, 0x0527C0U, 0x053F2BU, 0x054469U, 0x055C82U, 0x056D57U, 0x0575BCU, 0x058338U, 0x059BD3U, + 0x05AA06U, 0x05B2EDU, 0x05C9AFU, 0x05D144U, 0x05E091U, 0x05F87AU, 0x060B54U, 0x0613BFU, 0x06226AU, 0x063A81U, + 0x0641C3U, 0x065928U, 0x0668FDU, 0x067016U, 0x068692U, 0x069E79U, 0x06AFACU, 0x06B747U, 0x06CC05U, 0x06D4EEU, + 0x06E53BU, 0x06FDD0U, 0x070833U, 0x0710D8U, 0x07210DU, 0x0739E6U, 0x0742A4U, 0x075A4FU, 0x076B9AU, 0x077371U, + 0x0785F5U, 0x079D1EU, 0x07ACCBU, 0x07B420U, 0x07CF62U, 0x07D789U, 0x07E65CU, 0x07FEB7U, 0x0803DAU, 0x081B31U, + 0x082AE4U, 0x08320FU, 0x08494DU, 0x0851A6U, 0x086073U, 0x087898U, 0x088E1CU, 0x0896F7U, 0x08A722U, 0x08BFC9U, + 0x08C48BU, 0x08DC60U, 0x08EDB5U, 0x08F55EU, 0x0900BDU, 0x091856U, 0x092983U, 0x093168U, 0x094A2AU, 0x0952C1U, + 0x096314U, 0x097BFFU, 0x098D7BU, 0x099590U, 0x09A445U, 0x09BCAEU, 0x09C7ECU, 0x09DF07U, 0x09EED2U, 0x09F639U, + 0x0A0517U, 0x0A1DFCU, 0x0A2C29U, 0x0A34C2U, 0x0A4F80U, 0x0A576BU, 0x0A66BEU, 0x0A7E55U, 0x0A88D1U, 0x0A903AU, + 0x0AA1EFU, 0x0AB904U, 0x0AC246U, 0x0ADAADU, 0x0AEB78U, 0x0AF393U, 0x0B0670U, 0x0B1E9BU, 0x0B2F4EU, 0x0B37A5U, + 0x0B4CE7U, 0x0B540CU, 0x0B65D9U, 0x0B7D32U, 0x0B8BB6U, 0x0B935DU, 0x0BA288U, 0x0BBA63U, 0x0BC121U, 0x0BD9CAU, + 0x0BE81FU, 0x0BF0F4U, 0x0C0E43U, 0x0C16A8U, 0x0C277DU, 0x0C3F96U, 0x0C44D4U, 0x0C5C3FU, 0x0C6DEAU, 0x0C7501U, + 0x0C8385U, 0x0C9B6EU, 0x0CAABBU, 0x0CB250U, 0x0CC912U, 0x0CD1F9U, 0x0CE02CU, 0x0CF8C7U, 0x0D0D24U, 0x0D15CFU, + 0x0D241AU, 0x0D3CF1U, 0x0D47B3U, 0x0D5F58U, 0x0D6E8DU, 0x0D7666U, 0x0D80E2U, 0x0D9809U, 0x0DA9DCU, 0x0DB137U, + 0x0DCA75U, 0x0DD29EU, 0x0DE34BU, 0x0DFBA0U, 0x0E088EU, 0x0E1065U, 0x0E21B0U, 0x0E395BU, 0x0E4219U, 0x0E5AF2U, + 0x0E6B27U, 0x0E73CCU, 0x0E8548U, 0x0E9DA3U, 0x0EAC76U, 0x0EB49DU, 0x0ECFDFU, 0x0ED734U, 0x0EE6E1U, 0x0EFE0AU, + 0x0F0BE9U, 0x0F1302U, 0x0F22D7U, 0x0F3A3CU, 0x0F417EU, 0x0F5995U, 0x0F6840U, 0x0F70ABU, 0x0F862FU, 0x0F9EC4U, + 0x0FAF11U, 0x0FB7FAU, 0x0FCCB8U, 0x0FD453U, 0x0FE586U, 0x0FFD6DU, 0x1007B4U, 0x101F5FU, 0x102E8AU, 0x103661U, + 0x104D23U, 0x1055C8U, 0x10641DU, 0x107CF6U, 0x108A72U, 0x109299U, 0x10A34CU, 0x10BBA7U, 0x10C0E5U, 0x10D80EU, + 0x10E9DBU, 0x10F130U, 0x1104D3U, 0x111C38U, 0x112DEDU, 0x113506U, 0x114E44U, 0x1156AFU, 0x11677AU, 0x117F91U, + 0x118915U, 0x1191FEU, 0x11A02BU, 0x11B8C0U, 0x11C382U, 0x11DB69U, 0x11EABCU, 0x11F257U, 0x120179U, 0x121992U, + 0x122847U, 0x1230ACU, 0x124BEEU, 0x125305U, 0x1262D0U, 0x127A3BU, 0x128CBFU, 0x129454U, 0x12A581U, 0x12BD6AU, + 0x12C628U, 0x12DEC3U, 0x12EF16U, 0x12F7FDU, 0x13021EU, 0x131AF5U, 0x132B20U, 0x1333CBU, 0x134889U, 0x135062U, + 0x1361B7U, 0x13795CU, 0x138FD8U, 0x139733U, 0x13A6E6U, 0x13BE0DU, 0x13C54FU, 0x13DDA4U, 0x13EC71U, 0x13F49AU, + 0x140A2DU, 0x1412C6U, 0x142313U, 0x143BF8U, 0x1440BAU, 0x145851U, 0x146984U, 0x14716FU, 0x1487EBU, 0x149F00U, + 0x14AED5U, 0x14B63EU, 0x14CD7CU, 0x14D597U, 0x14E442U, 0x14FCA9U, 0x15094AU, 0x1511A1U, 0x152074U, 0x15389FU, + 0x1543DDU, 0x155B36U, 0x156AE3U, 0x157208U, 0x15848CU, 0x159C67U, 0x15ADB2U, 0x15B559U, 0x15CE1BU, 0x15D6F0U, + 0x15E725U, 0x15FFCEU, 0x160CE0U, 0x16140BU, 0x1625DEU, 0x163D35U, 0x164677U, 0x165E9CU, 0x166F49U, 0x1677A2U, + 0x168126U, 0x1699CDU, 0x16A818U, 0x16B0F3U, 0x16CBB1U, 0x16D35AU, 0x16E28FU, 0x16FA64U, 0x170F87U, 0x17176CU, + 0x1726B9U, 0x173E52U, 0x174510U, 0x175DFBU, 0x176C2EU, 0x1774C5U, 0x178241U, 0x179AAAU, 0x17AB7FU, 0x17B394U, + 0x17C8D6U, 0x17D03DU, 0x17E1E8U, 0x17F903U, 0x18046EU, 0x181C85U, 0x182D50U, 0x1835BBU, 0x184EF9U, 0x185612U, + 0x1867C7U, 0x187F2CU, 0x1889A8U, 0x189143U, 0x18A096U, 0x18B87DU, 0x18C33FU, 0x18DBD4U, 0x18EA01U, 0x18F2EAU, + 0x190709U, 0x191FE2U, 0x192E37U, 0x1936DCU, 0x194D9EU, 0x195575U, 0x1964A0U, 0x197C4BU, 0x198ACFU, 0x199224U, + 0x19A3F1U, 0x19BB1AU, 0x19C058U, 0x19D8B3U, 0x19E966U, 0x19F18DU, 0x1A02A3U, 0x1A1A48U, 0x1A2B9DU, 0x1A3376U, + 0x1A4834U, 0x1A50DFU, 0x1A610AU, 0x1A79E1U, 0x1A8F65U, 0x1A978EU, 0x1AA65BU, 0x1ABEB0U, 0x1AC5F2U, 0x1ADD19U, + 0x1AECCCU, 0x1AF427U, 0x1B01C4U, 0x1B192FU, 0x1B28FAU, 0x1B3011U, 0x1B4B53U, 0x1B53B8U, 0x1B626DU, 0x1B7A86U, + 0x1B8C02U, 0x1B94E9U, 0x1BA53CU, 0x1BBDD7U, 0x1BC695U, 0x1BDE7EU, 0x1BEFABU, 0x1BF740U, 0x1C09F7U, 0x1C111CU, + 0x1C20C9U, 0x1C3822U, 0x1C4360U, 0x1C5B8BU, 0x1C6A5EU, 0x1C72B5U, 0x1C8431U, 0x1C9CDAU, 0x1CAD0FU, 0x1CB5E4U, + 0x1CCEA6U, 0x1CD64DU, 0x1CE798U, 0x1CFF73U, 0x1D0A90U, 0x1D127BU, 0x1D23AEU, 0x1D3B45U, 0x1D4007U, 0x1D58ECU, + 0x1D6939U, 0x1D71D2U, 0x1D8756U, 0x1D9FBDU, 0x1DAE68U, 0x1DB683U, 0x1DCDC1U, 0x1DD52AU, 0x1DE4FFU, 0x1DFC14U, + 0x1E0F3AU, 0x1E17D1U, 0x1E2604U, 0x1E3EEFU, 0x1E45ADU, 0x1E5D46U, 0x1E6C93U, 0x1E7478U, 0x1E82FCU, 0x1E9A17U, + 0x1EABC2U, 0x1EB329U, 0x1EC86BU, 0x1ED080U, 0x1EE155U, 0x1EF9BEU, 0x1F0C5DU, 0x1F14B6U, 0x1F2563U, 0x1F3D88U, + 0x1F46CAU, 0x1F5E21U, 0x1F6FF4U, 0x1F771FU, 0x1F819BU, 0x1F9970U, 0x1FA8A5U, 0x1FB04EU, 0x1FCB0CU, 0x1FD3E7U, + 0x1FE232U, 0x1FFAD9U, 0x200F68U, 0x201783U, 0x202656U, 0x203EBDU, 0x2045FFU, 0x205D14U, 0x206CC1U, 0x20742AU, + 0x2082AEU, 0x209A45U, 0x20AB90U, 0x20B37BU, 0x20C839U, 0x20D0D2U, 0x20E107U, 0x20F9ECU, 0x210C0FU, 0x2114E4U, + 0x212531U, 0x213DDAU, 0x214698U, 0x215E73U, 0x216FA6U, 0x21774DU, 0x2181C9U, 0x219922U, 0x21A8F7U, 0x21B01CU, + 0x21CB5EU, 0x21D3B5U, 0x21E260U, 0x21FA8BU, 0x2209A5U, 0x22114EU, 0x22209BU, 0x223870U, 0x224332U, 0x225BD9U, + 0x226A0CU, 0x2272E7U, 0x228463U, 0x229C88U, 0x22AD5DU, 0x22B5B6U, 0x22CEF4U, 0x22D61FU, 0x22E7CAU, 0x22FF21U, + 0x230AC2U, 0x231229U, 0x2323FCU, 0x233B17U, 0x234055U, 0x2358BEU, 0x23696BU, 0x237180U, 0x238704U, 0x239FEFU, + 0x23AE3AU, 0x23B6D1U, 0x23CD93U, 0x23D578U, 0x23E4ADU, 0x23FC46U, 0x2402F1U, 0x241A1AU, 0x242BCFU, 0x243324U, + 0x244866U, 0x24508DU, 0x246158U, 0x2479B3U, 0x248F37U, 0x2497DCU, 0x24A609U, 0x24BEE2U, 0x24C5A0U, 0x24DD4BU, + 0x24EC9EU, 0x24F475U, 0x250196U, 0x25197DU, 0x2528A8U, 0x253043U, 0x254B01U, 0x2553EAU, 0x25623FU, 0x257AD4U, + 0x258C50U, 0x2594BBU, 0x25A56EU, 0x25BD85U, 0x25C6C7U, 0x25DE2CU, 0x25EFF9U, 0x25F712U, 0x26043CU, 0x261CD7U, + 0x262D02U, 0x2635E9U, 0x264EABU, 0x265640U, 0x266795U, 0x267F7EU, 0x2689FAU, 0x269111U, 0x26A0C4U, 0x26B82FU, + 0x26C36DU, 0x26DB86U, 0x26EA53U, 0x26F2B8U, 0x27075BU, 0x271FB0U, 0x272E65U, 0x27368EU, 0x274DCCU, 0x275527U, + 0x2764F2U, 0x277C19U, 0x278A9DU, 0x279276U, 0x27A3A3U, 0x27BB48U, 0x27C00AU, 0x27D8E1U, 0x27E934U, 0x27F1DFU, + 0x280CB2U, 0x281459U, 0x28258CU, 0x283D67U, 0x284625U, 0x285ECEU, 0x286F1BU, 0x2877F0U, 0x288174U, 0x28999FU, + 0x28A84AU, 0x28B0A1U, 0x28CBE3U, 0x28D308U, 0x28E2DDU, 0x28FA36U, 0x290FD5U, 0x29173EU, 0x2926EBU, 0x293E00U, + 0x294542U, 0x295DA9U, 0x296C7CU, 0x297497U, 0x298213U, 0x299AF8U, 0x29AB2DU, 0x29B3C6U, 0x29C884U, 0x29D06FU, + 0x29E1BAU, 0x29F951U, 0x2A0A7FU, 0x2A1294U, 0x2A2341U, 0x2A3BAAU, 0x2A40E8U, 0x2A5803U, 0x2A69D6U, 0x2A713DU, + 0x2A87B9U, 0x2A9F52U, 0x2AAE87U, 0x2AB66CU, 0x2ACD2EU, 0x2AD5C5U, 0x2AE410U, 0x2AFCFBU, 0x2B0918U, 0x2B11F3U, + 0x2B2026U, 0x2B38CDU, 0x2B438FU, 0x2B5B64U, 0x2B6AB1U, 0x2B725AU, 0x2B84DEU, 0x2B9C35U, 0x2BADE0U, 0x2BB50BU, + 0x2BCE49U, 0x2BD6A2U, 0x2BE777U, 0x2BFF9CU, 0x2C012BU, 0x2C19C0U, 0x2C2815U, 0x2C30FEU, 0x2C4BBCU, 0x2C5357U, + 0x2C6282U, 0x2C7A69U, 0x2C8CEDU, 0x2C9406U, 0x2CA5D3U, 0x2CBD38U, 0x2CC67AU, 0x2CDE91U, 0x2CEF44U, 0x2CF7AFU, + 0x2D024CU, 0x2D1AA7U, 0x2D2B72U, 0x2D3399U, 0x2D48DBU, 0x2D5030U, 0x2D61E5U, 0x2D790EU, 0x2D8F8AU, 0x2D9761U, + 0x2DA6B4U, 0x2DBE5FU, 0x2DC51DU, 0x2DDDF6U, 0x2DEC23U, 0x2DF4C8U, 0x2E07E6U, 0x2E1F0DU, 0x2E2ED8U, 0x2E3633U, + 0x2E4D71U, 0x2E559AU, 0x2E644FU, 0x2E7CA4U, 0x2E8A20U, 0x2E92CBU, 0x2EA31EU, 0x2EBBF5U, 0x2EC0B7U, 0x2ED85CU, + 0x2EE989U, 0x2EF162U, 0x2F0481U, 0x2F1C6AU, 0x2F2DBFU, 0x2F3554U, 0x2F4E16U, 0x2F56FDU, 0x2F6728U, 0x2F7FC3U, + 0x2F8947U, 0x2F91ACU, 0x2FA079U, 0x2FB892U, 0x2FC3D0U, 0x2FDB3BU, 0x2FEAEEU, 0x2FF205U, 0x3008DCU, 0x301037U, + 0x3021E2U, 0x303909U, 0x30424BU, 0x305AA0U, 0x306B75U, 0x30739EU, 0x30851AU, 0x309DF1U, 0x30AC24U, 0x30B4CFU, + 0x30CF8DU, 0x30D766U, 0x30E6B3U, 0x30FE58U, 0x310BBBU, 0x311350U, 0x312285U, 0x313A6EU, 0x31412CU, 0x3159C7U, + 0x316812U, 0x3170F9U, 0x31867DU, 0x319E96U, 0x31AF43U, 0x31B7A8U, 0x31CCEAU, 0x31D401U, 0x31E5D4U, 0x31FD3FU, + 0x320E11U, 0x3216FAU, 0x32272FU, 0x323FC4U, 0x324486U, 0x325C6DU, 0x326DB8U, 0x327553U, 0x3283D7U, 0x329B3CU, + 0x32AAE9U, 0x32B202U, 0x32C940U, 0x32D1ABU, 0x32E07EU, 0x32F895U, 0x330D76U, 0x33159DU, 0x332448U, 0x333CA3U, + 0x3347E1U, 0x335F0AU, 0x336EDFU, 0x337634U, 0x3380B0U, 0x33985BU, 0x33A98EU, 0x33B165U, 0x33CA27U, 0x33D2CCU, + 0x33E319U, 0x33FBF2U, 0x340545U, 0x341DAEU, 0x342C7BU, 0x343490U, 0x344FD2U, 0x345739U, 0x3466ECU, 0x347E07U, + 0x348883U, 0x349068U, 0x34A1BDU, 0x34B956U, 0x34C214U, 0x34DAFFU, 0x34EB2AU, 0x34F3C1U, 0x350622U, 0x351EC9U, + 0x352F1CU, 0x3537F7U, 0x354CB5U, 0x35545EU, 0x35658BU, 0x357D60U, 0x358BE4U, 0x35930FU, 0x35A2DAU, 0x35BA31U, + 0x35C173U, 0x35D998U, 0x35E84DU, 0x35F0A6U, 0x360388U, 0x361B63U, 0x362AB6U, 0x36325DU, 0x36491FU, 0x3651F4U, + 0x366021U, 0x3678CAU, 0x368E4EU, 0x3696A5U, 0x36A770U, 0x36BF9BU, 0x36C4D9U, 0x36DC32U, 0x36EDE7U, 0x36F50CU, + 0x3700EFU, 0x371804U, 0x3729D1U, 0x37313AU, 0x374A78U, 0x375293U, 0x376346U, 0x377BADU, 0x378D29U, 0x3795C2U, + 0x37A417U, 0x37BCFCU, 0x37C7BEU, 0x37DF55U, 0x37EE80U, 0x37F66BU, 0x380B06U, 0x3813EDU, 0x382238U, 0x383AD3U, + 0x384191U, 0x38597AU, 0x3868AFU, 0x387044U, 0x3886C0U, 0x389E2BU, 0x38AFFEU, 0x38B715U, 0x38CC57U, 0x38D4BCU, + 0x38E569U, 0x38FD82U, 0x390861U, 0x39108AU, 0x39215FU, 0x3939B4U, 0x3942F6U, 0x395A1DU, 0x396BC8U, 0x397323U, + 0x3985A7U, 0x399D4CU, 0x39AC99U, 0x39B472U, 0x39CF30U, 0x39D7DBU, 0x39E60EU, 0x39FEE5U, 0x3A0DCBU, 0x3A1520U, + 0x3A24F5U, 0x3A3C1EU, 0x3A475CU, 0x3A5FB7U, 0x3A6E62U, 0x3A7689U, 0x3A800DU, 0x3A98E6U, 0x3AA933U, 0x3AB1D8U, + 0x3ACA9AU, 0x3AD271U, 0x3AE3A4U, 0x3AFB4FU, 0x3B0EACU, 0x3B1647U, 0x3B2792U, 0x3B3F79U, 0x3B443BU, 0x3B5CD0U, + 0x3B6D05U, 0x3B75EEU, 0x3B836AU, 0x3B9B81U, 0x3BAA54U, 0x3BB2BFU, 0x3BC9FDU, 0x3BD116U, 0x3BE0C3U, 0x3BF828U, + 0x3C069FU, 0x3C1E74U, 0x3C2FA1U, 0x3C374AU, 0x3C4C08U, 0x3C54E3U, 0x3C6536U, 0x3C7DDDU, 0x3C8B59U, 0x3C93B2U, + 0x3CA267U, 0x3CBA8CU, 0x3CC1CEU, 0x3CD925U, 0x3CE8F0U, 0x3CF01BU, 0x3D05F8U, 0x3D1D13U, 0x3D2CC6U, 0x3D342DU, + 0x3D4F6FU, 0x3D5784U, 0x3D6651U, 0x3D7EBAU, 0x3D883EU, 0x3D90D5U, 0x3DA100U, 0x3DB9EBU, 0x3DC2A9U, 0x3DDA42U, + 0x3DEB97U, 0x3DF37CU, 0x3E0052U, 0x3E18B9U, 0x3E296CU, 0x3E3187U, 0x3E4AC5U, 0x3E522EU, 0x3E63FBU, 0x3E7B10U, + 0x3E8D94U, 0x3E957FU, 0x3EA4AAU, 0x3EBC41U, 0x3EC703U, 0x3EDFE8U, 0x3EEE3DU, 0x3EF6D6U, 0x3F0335U, 0x3F1BDEU, + 0x3F2A0BU, 0x3F32E0U, 0x3F49A2U, 0x3F5149U, 0x3F609CU, 0x3F7877U, 0x3F8EF3U, 0x3F9618U, 0x3FA7CDU, 0x3FBF26U, + 0x3FC464U, 0x3FDC8FU, 0x3FED5AU, 0x3FF5B1U, 0x40063BU, 0x401ED0U, 0x402F05U, 0x4037EEU, 0x404CACU, 0x405447U, + 0x406592U, 0x407D79U, 0x408BFDU, 0x409316U, 0x40A2C3U, 0x40BA28U, 0x40C16AU, 0x40D981U, 0x40E854U, 0x40F0BFU, + 0x41055CU, 0x411DB7U, 0x412C62U, 0x413489U, 0x414FCBU, 0x415720U, 0x4166F5U, 0x417E1EU, 0x41889AU, 0x419071U, + 0x41A1A4U, 0x41B94FU, 0x41C20DU, 0x41DAE6U, 0x41EB33U, 0x41F3D8U, 0x4200F6U, 0x42181DU, 0x4229C8U, 0x423123U, + 0x424A61U, 0x42528AU, 0x42635FU, 0x427BB4U, 0x428D30U, 0x4295DBU, 0x42A40EU, 0x42BCE5U, 0x42C7A7U, 0x42DF4CU, + 0x42EE99U, 0x42F672U, 0x430391U, 0x431B7AU, 0x432AAFU, 0x433244U, 0x434906U, 0x4351EDU, 0x436038U, 0x4378D3U, + 0x438E57U, 0x4396BCU, 0x43A769U, 0x43BF82U, 0x43C4C0U, 0x43DC2BU, 0x43EDFEU, 0x43F515U, 0x440BA2U, 0x441349U, + 0x44229CU, 0x443A77U, 0x444135U, 0x4459DEU, 0x44680BU, 0x4470E0U, 0x448664U, 0x449E8FU, 0x44AF5AU, 0x44B7B1U, + 0x44CCF3U, 0x44D418U, 0x44E5CDU, 0x44FD26U, 0x4508C5U, 0x45102EU, 0x4521FBU, 0x453910U, 0x454252U, 0x455AB9U, + 0x456B6CU, 0x457387U, 0x458503U, 0x459DE8U, 0x45AC3DU, 0x45B4D6U, 0x45CF94U, 0x45D77FU, 0x45E6AAU, 0x45FE41U, + 0x460D6FU, 0x461584U, 0x462451U, 0x463CBAU, 0x4647F8U, 0x465F13U, 0x466EC6U, 0x46762DU, 0x4680A9U, 0x469842U, + 0x46A997U, 0x46B17CU, 0x46CA3EU, 0x46D2D5U, 0x46E300U, 0x46FBEBU, 0x470E08U, 0x4716E3U, 0x472736U, 0x473FDDU, + 0x47449FU, 0x475C74U, 0x476DA1U, 0x47754AU, 0x4783CEU, 0x479B25U, 0x47AAF0U, 0x47B21BU, 0x47C959U, 0x47D1B2U, + 0x47E067U, 0x47F88CU, 0x4805E1U, 0x481D0AU, 0x482CDFU, 0x483434U, 0x484F76U, 0x48579DU, 0x486648U, 0x487EA3U, + 0x488827U, 0x4890CCU, 0x48A119U, 0x48B9F2U, 0x48C2B0U, 0x48DA5BU, 0x48EB8EU, 0x48F365U, 0x490686U, 0x491E6DU, + 0x492FB8U, 0x493753U, 0x494C11U, 0x4954FAU, 0x49652FU, 0x497DC4U, 0x498B40U, 0x4993ABU, 0x49A27EU, 0x49BA95U, + 0x49C1D7U, 0x49D93CU, 0x49E8E9U, 0x49F002U, 0x4A032CU, 0x4A1BC7U, 0x4A2A12U, 0x4A32F9U, 0x4A49BBU, 0x4A5150U, + 0x4A6085U, 0x4A786EU, 0x4A8EEAU, 0x4A9601U, 0x4AA7D4U, 0x4ABF3FU, 0x4AC47DU, 0x4ADC96U, 0x4AED43U, 0x4AF5A8U, + 0x4B004BU, 0x4B18A0U, 0x4B2975U, 0x4B319EU, 0x4B4ADCU, 0x4B5237U, 0x4B63E2U, 0x4B7B09U, 0x4B8D8DU, 0x4B9566U, + 0x4BA4B3U, 0x4BBC58U, 0x4BC71AU, 0x4BDFF1U, 0x4BEE24U, 0x4BF6CFU, 0x4C0878U, 0x4C1093U, 0x4C2146U, 0x4C39ADU, + 0x4C42EFU, 0x4C5A04U, 0x4C6BD1U, 0x4C733AU, 0x4C85BEU, 0x4C9D55U, 0x4CAC80U, 0x4CB46BU, 0x4CCF29U, 0x4CD7C2U, + 0x4CE617U, 0x4CFEFCU, 0x4D0B1FU, 0x4D13F4U, 0x4D2221U, 0x4D3ACAU, 0x4D4188U, 0x4D5963U, 0x4D68B6U, 0x4D705DU, + 0x4D86D9U, 0x4D9E32U, 0x4DAFE7U, 0x4DB70CU, 0x4DCC4EU, 0x4DD4A5U, 0x4DE570U, 0x4DFD9BU, 0x4E0EB5U, 0x4E165EU, + 0x4E278BU, 0x4E3F60U, 0x4E4422U, 0x4E5CC9U, 0x4E6D1CU, 0x4E75F7U, 0x4E8373U, 0x4E9B98U, 0x4EAA4DU, 0x4EB2A6U, + 0x4EC9E4U, 0x4ED10FU, 0x4EE0DAU, 0x4EF831U, 0x4F0DD2U, 0x4F1539U, 0x4F24ECU, 0x4F3C07U, 0x4F4745U, 0x4F5FAEU, + 0x4F6E7BU, 0x4F7690U, 0x4F8014U, 0x4F98FFU, 0x4FA92AU, 0x4FB1C1U, 0x4FCA83U, 0x4FD268U, 0x4FE3BDU, 0x4FFB56U, + 0x50018FU, 0x501964U, 0x5028B1U, 0x50305AU, 0x504B18U, 0x5053F3U, 0x506226U, 0x507ACDU, 0x508C49U, 0x5094A2U, + 0x50A577U, 0x50BD9CU, 0x50C6DEU, 0x50DE35U, 0x50EFE0U, 0x50F70BU, 0x5102E8U, 0x511A03U, 0x512BD6U, 0x51333DU, + 0x51487FU, 0x515094U, 0x516141U, 0x5179AAU, 0x518F2EU, 0x5197C5U, 0x51A610U, 0x51BEFBU, 0x51C5B9U, 0x51DD52U, + 0x51EC87U, 0x51F46CU, 0x520742U, 0x521FA9U, 0x522E7CU, 0x523697U, 0x524DD5U, 0x52553EU, 0x5264EBU, 0x527C00U, + 0x528A84U, 0x52926FU, 0x52A3BAU, 0x52BB51U, 0x52C013U, 0x52D8F8U, 0x52E92DU, 0x52F1C6U, 0x530425U, 0x531CCEU, + 0x532D1BU, 0x5335F0U, 0x534EB2U, 0x535659U, 0x53678CU, 0x537F67U, 0x5389E3U, 0x539108U, 0x53A0DDU, 0x53B836U, + 0x53C374U, 0x53DB9FU, 0x53EA4AU, 0x53F2A1U, 0x540C16U, 0x5414FDU, 0x542528U, 0x543DC3U, 0x544681U, 0x545E6AU, + 0x546FBFU, 0x547754U, 0x5481D0U, 0x54993BU, 0x54A8EEU, 0x54B005U, 0x54CB47U, 0x54D3ACU, 0x54E279U, 0x54FA92U, + 0x550F71U, 0x55179AU, 0x55264FU, 0x553EA4U, 0x5545E6U, 0x555D0DU, 0x556CD8U, 0x557433U, 0x5582B7U, 0x559A5CU, + 0x55AB89U, 0x55B362U, 0x55C820U, 0x55D0CBU, 0x55E11EU, 0x55F9F5U, 0x560ADBU, 0x561230U, 0x5623E5U, 0x563B0EU, + 0x56404CU, 0x5658A7U, 0x566972U, 0x567199U, 0x56871DU, 0x569FF6U, 0x56AE23U, 0x56B6C8U, 0x56CD8AU, 0x56D561U, + 0x56E4B4U, 0x56FC5FU, 0x5709BCU, 0x571157U, 0x572082U, 0x573869U, 0x57432BU, 0x575BC0U, 0x576A15U, 0x5772FEU, + 0x57847AU, 0x579C91U, 0x57AD44U, 0x57B5AFU, 0x57CEEDU, 0x57D606U, 0x57E7D3U, 0x57FF38U, 0x580255U, 0x581ABEU, + 0x582B6BU, 0x583380U, 0x5848C2U, 0x585029U, 0x5861FCU, 0x587917U, 0x588F93U, 0x589778U, 0x58A6ADU, 0x58BE46U, + 0x58C504U, 0x58DDEFU, 0x58EC3AU, 0x58F4D1U, 0x590132U, 0x5919D9U, 0x59280CU, 0x5930E7U, 0x594BA5U, 0x59534EU, + 0x59629BU, 0x597A70U, 0x598CF4U, 0x59941FU, 0x59A5CAU, 0x59BD21U, 0x59C663U, 0x59DE88U, 0x59EF5DU, 0x59F7B6U, + 0x5A0498U, 0x5A1C73U, 0x5A2DA6U, 0x5A354DU, 0x5A4E0FU, 0x5A56E4U, 0x5A6731U, 0x5A7FDAU, 0x5A895EU, 0x5A91B5U, + 0x5AA060U, 0x5AB88BU, 0x5AC3C9U, 0x5ADB22U, 0x5AEAF7U, 0x5AF21CU, 0x5B07FFU, 0x5B1F14U, 0x5B2EC1U, 0x5B362AU, + 0x5B4D68U, 0x5B5583U, 0x5B6456U, 0x5B7CBDU, 0x5B8A39U, 0x5B92D2U, 0x5BA307U, 0x5BBBECU, 0x5BC0AEU, 0x5BD845U, + 0x5BE990U, 0x5BF17BU, 0x5C0FCCU, 0x5C1727U, 0x5C26F2U, 0x5C3E19U, 0x5C455BU, 0x5C5DB0U, 0x5C6C65U, 0x5C748EU, + 0x5C820AU, 0x5C9AE1U, 0x5CAB34U, 0x5CB3DFU, 0x5CC89DU, 0x5CD076U, 0x5CE1A3U, 0x5CF948U, 0x5D0CABU, 0x5D1440U, + 0x5D2595U, 0x5D3D7EU, 0x5D463CU, 0x5D5ED7U, 0x5D6F02U, 0x5D77E9U, 0x5D816DU, 0x5D9986U, 0x5DA853U, 0x5DB0B8U, + 0x5DCBFAU, 0x5DD311U, 0x5DE2C4U, 0x5DFA2FU, 0x5E0901U, 0x5E11EAU, 0x5E203FU, 0x5E38D4U, 0x5E4396U, 0x5E5B7DU, + 0x5E6AA8U, 0x5E7243U, 0x5E84C7U, 0x5E9C2CU, 0x5EADF9U, 0x5EB512U, 0x5ECE50U, 0x5ED6BBU, 0x5EE76EU, 0x5EFF85U, + 0x5F0A66U, 0x5F128DU, 0x5F2358U, 0x5F3BB3U, 0x5F40F1U, 0x5F581AU, 0x5F69CFU, 0x5F7124U, 0x5F87A0U, 0x5F9F4BU, + 0x5FAE9EU, 0x5FB675U, 0x5FCD37U, 0x5FD5DCU, 0x5FE409U, 0x5FFCE2U, 0x600953U, 0x6011B8U, 0x60206DU, 0x603886U, + 0x6043C4U, 0x605B2FU, 0x606AFAU, 0x607211U, 0x608495U, 0x609C7EU, 0x60ADABU, 0x60B540U, 0x60CE02U, 0x60D6E9U, + 0x60E73CU, 0x60FFD7U, 0x610A34U, 0x6112DFU, 0x61230AU, 0x613BE1U, 0x6140A3U, 0x615848U, 0x61699DU, 0x617176U, + 0x6187F2U, 0x619F19U, 0x61AECCU, 0x61B627U, 0x61CD65U, 0x61D58EU, 0x61E45BU, 0x61FCB0U, 0x620F9EU, 0x621775U, + 0x6226A0U, 0x623E4BU, 0x624509U, 0x625DE2U, 0x626C37U, 0x6274DCU, 0x628258U, 0x629AB3U, 0x62AB66U, 0x62B38DU, + 0x62C8CFU, 0x62D024U, 0x62E1F1U, 0x62F91AU, 0x630CF9U, 0x631412U, 0x6325C7U, 0x633D2CU, 0x63466EU, 0x635E85U, + 0x636F50U, 0x6377BBU, 0x63813FU, 0x6399D4U, 0x63A801U, 0x63B0EAU, 0x63CBA8U, 0x63D343U, 0x63E296U, 0x63FA7DU, + 0x6404CAU, 0x641C21U, 0x642DF4U, 0x64351FU, 0x644E5DU, 0x6456B6U, 0x646763U, 0x647F88U, 0x64890CU, 0x6491E7U, + 0x64A032U, 0x64B8D9U, 0x64C39BU, 0x64DB70U, 0x64EAA5U, 0x64F24EU, 0x6507ADU, 0x651F46U, 0x652E93U, 0x653678U, + 0x654D3AU, 0x6555D1U, 0x656404U, 0x657CEFU, 0x658A6BU, 0x659280U, 0x65A355U, 0x65BBBEU, 0x65C0FCU, 0x65D817U, + 0x65E9C2U, 0x65F129U, 0x660207U, 0x661AECU, 0x662B39U, 0x6633D2U, 0x664890U, 0x66507BU, 0x6661AEU, 0x667945U, + 0x668FC1U, 0x66972AU, 0x66A6FFU, 0x66BE14U, 0x66C556U, 0x66DDBDU, 0x66EC68U, 0x66F483U, 0x670160U, 0x67198BU, + 0x67285EU, 0x6730B5U, 0x674BF7U, 0x67531CU, 0x6762C9U, 0x677A22U, 0x678CA6U, 0x67944DU, 0x67A598U, 0x67BD73U, + 0x67C631U, 0x67DEDAU, 0x67EF0FU, 0x67F7E4U, 0x680A89U, 0x681262U, 0x6823B7U, 0x683B5CU, 0x68401EU, 0x6858F5U, + 0x686920U, 0x6871CBU, 0x68874FU, 0x689FA4U, 0x68AE71U, 0x68B69AU, 0x68CDD8U, 0x68D533U, 0x68E4E6U, 0x68FC0DU, + 0x6909EEU, 0x691105U, 0x6920D0U, 0x69383BU, 0x694379U, 0x695B92U, 0x696A47U, 0x6972ACU, 0x698428U, 0x699CC3U, + 0x69AD16U, 0x69B5FDU, 0x69CEBFU, 0x69D654U, 0x69E781U, 0x69FF6AU, 0x6A0C44U, 0x6A14AFU, 0x6A257AU, 0x6A3D91U, + 0x6A46D3U, 0x6A5E38U, 0x6A6FEDU, 0x6A7706U, 0x6A8182U, 0x6A9969U, 0x6AA8BCU, 0x6AB057U, 0x6ACB15U, 0x6AD3FEU, + 0x6AE22BU, 0x6AFAC0U, 0x6B0F23U, 0x6B17C8U, 0x6B261DU, 0x6B3EF6U, 0x6B45B4U, 0x6B5D5FU, 0x6B6C8AU, 0x6B7461U, + 0x6B82E5U, 0x6B9A0EU, 0x6BABDBU, 0x6BB330U, 0x6BC872U, 0x6BD099U, 0x6BE14CU, 0x6BF9A7U, 0x6C0710U, 0x6C1FFBU, + 0x6C2E2EU, 0x6C36C5U, 0x6C4D87U, 0x6C556CU, 0x6C64B9U, 0x6C7C52U, 0x6C8AD6U, 0x6C923DU, 0x6CA3E8U, 0x6CBB03U, + 0x6CC041U, 0x6CD8AAU, 0x6CE97FU, 0x6CF194U, 0x6D0477U, 0x6D1C9CU, 0x6D2D49U, 0x6D35A2U, 0x6D4EE0U, 0x6D560BU, + 0x6D67DEU, 0x6D7F35U, 0x6D89B1U, 0x6D915AU, 0x6DA08FU, 0x6DB864U, 0x6DC326U, 0x6DDBCDU, 0x6DEA18U, 0x6DF2F3U, + 0x6E01DDU, 0x6E1936U, 0x6E28E3U, 0x6E3008U, 0x6E4B4AU, 0x6E53A1U, 0x6E6274U, 0x6E7A9FU, 0x6E8C1BU, 0x6E94F0U, + 0x6EA525U, 0x6EBDCEU, 0x6EC68CU, 0x6EDE67U, 0x6EEFB2U, 0x6EF759U, 0x6F02BAU, 0x6F1A51U, 0x6F2B84U, 0x6F336FU, + 0x6F482DU, 0x6F50C6U, 0x6F6113U, 0x6F79F8U, 0x6F8F7CU, 0x6F9797U, 0x6FA642U, 0x6FBEA9U, 0x6FC5EBU, 0x6FDD00U, + 0x6FECD5U, 0x6FF43EU, 0x700EE7U, 0x70160CU, 0x7027D9U, 0x703F32U, 0x704470U, 0x705C9BU, 0x706D4EU, 0x7075A5U, + 0x708321U, 0x709BCAU, 0x70AA1FU, 0x70B2F4U, 0x70C9B6U, 0x70D15DU, 0x70E088U, 0x70F863U, 0x710D80U, 0x71156BU, + 0x7124BEU, 0x713C55U, 0x714717U, 0x715FFCU, 0x716E29U, 0x7176C2U, 0x718046U, 0x7198ADU, 0x71A978U, 0x71B193U, + 0x71CAD1U, 0x71D23AU, 0x71E3EFU, 0x71FB04U, 0x72082AU, 0x7210C1U, 0x722114U, 0x7239FFU, 0x7242BDU, 0x725A56U, + 0x726B83U, 0x727368U, 0x7285ECU, 0x729D07U, 0x72ACD2U, 0x72B439U, 0x72CF7BU, 0x72D790U, 0x72E645U, 0x72FEAEU, + 0x730B4DU, 0x7313A6U, 0x732273U, 0x733A98U, 0x7341DAU, 0x735931U, 0x7368E4U, 0x73700FU, 0x73868BU, 0x739E60U, + 0x73AFB5U, 0x73B75EU, 0x73CC1CU, 0x73D4F7U, 0x73E522U, 0x73FDC9U, 0x74037EU, 0x741B95U, 0x742A40U, 0x7432ABU, + 0x7449E9U, 0x745102U, 0x7460D7U, 0x74783CU, 0x748EB8U, 0x749653U, 0x74A786U, 0x74BF6DU, 0x74C42FU, 0x74DCC4U, + 0x74ED11U, 0x74F5FAU, 0x750019U, 0x7518F2U, 0x752927U, 0x7531CCU, 0x754A8EU, 0x755265U, 0x7563B0U, 0x757B5BU, + 0x758DDFU, 0x759534U, 0x75A4E1U, 0x75BC0AU, 0x75C748U, 0x75DFA3U, 0x75EE76U, 0x75F69DU, 0x7605B3U, 0x761D58U, + 0x762C8DU, 0x763466U, 0x764F24U, 0x7657CFU, 0x76661AU, 0x767EF1U, 0x768875U, 0x76909EU, 0x76A14BU, 0x76B9A0U, + 0x76C2E2U, 0x76DA09U, 0x76EBDCU, 0x76F337U, 0x7706D4U, 0x771E3FU, 0x772FEAU, 0x773701U, 0x774C43U, 0x7754A8U, + 0x77657DU, 0x777D96U, 0x778B12U, 0x7793F9U, 0x77A22CU, 0x77BAC7U, 0x77C185U, 0x77D96EU, 0x77E8BBU, 0x77F050U, + 0x780D3DU, 0x7815D6U, 0x782403U, 0x783CE8U, 0x7847AAU, 0x785F41U, 0x786E94U, 0x78767FU, 0x7880FBU, 0x789810U, + 0x78A9C5U, 0x78B12EU, 0x78CA6CU, 0x78D287U, 0x78E352U, 0x78FBB9U, 0x790E5AU, 0x7916B1U, 0x792764U, 0x793F8FU, + 0x7944CDU, 0x795C26U, 0x796DF3U, 0x797518U, 0x79839CU, 0x799B77U, 0x79AAA2U, 0x79B249U, 0x79C90BU, 0x79D1E0U, + 0x79E035U, 0x79F8DEU, 0x7A0BF0U, 0x7A131BU, 0x7A22CEU, 0x7A3A25U, 0x7A4167U, 0x7A598CU, 0x7A6859U, 0x7A70B2U, + 0x7A8636U, 0x7A9EDDU, 0x7AAF08U, 0x7AB7E3U, 0x7ACCA1U, 0x7AD44AU, 0x7AE59FU, 0x7AFD74U, 0x7B0897U, 0x7B107CU, + 0x7B21A9U, 0x7B3942U, 0x7B4200U, 0x7B5AEBU, 0x7B6B3EU, 0x7B73D5U, 0x7B8551U, 0x7B9DBAU, 0x7BAC6FU, 0x7BB484U, + 0x7BCFC6U, 0x7BD72DU, 0x7BE6F8U, 0x7BFE13U, 0x7C00A4U, 0x7C184FU, 0x7C299AU, 0x7C3171U, 0x7C4A33U, 0x7C52D8U, + 0x7C630DU, 0x7C7BE6U, 0x7C8D62U, 0x7C9589U, 0x7CA45CU, 0x7CBCB7U, 0x7CC7F5U, 0x7CDF1EU, 0x7CEECBU, 0x7CF620U, + 0x7D03C3U, 0x7D1B28U, 0x7D2AFDU, 0x7D3216U, 0x7D4954U, 0x7D51BFU, 0x7D606AU, 0x7D7881U, 0x7D8E05U, 0x7D96EEU, + 0x7DA73BU, 0x7DBFD0U, 0x7DC492U, 0x7DDC79U, 0x7DEDACU, 0x7DF547U, 0x7E0669U, 0x7E1E82U, 0x7E2F57U, 0x7E37BCU, + 0x7E4CFEU, 0x7E5415U, 0x7E65C0U, 0x7E7D2BU, 0x7E8BAFU, 0x7E9344U, 0x7EA291U, 0x7EBA7AU, 0x7EC138U, 0x7ED9D3U, + 0x7EE806U, 0x7EF0EDU, 0x7F050EU, 0x7F1DE5U, 0x7F2C30U, 0x7F34DBU, 0x7F4F99U, 0x7F5772U, 0x7F66A7U, 0x7F7E4CU, + 0x7F88C8U, 0x7F9023U, 0x7FA1F6U, 0x7FB91DU, 0x7FC25FU, 0x7FDAB4U, 0x7FEB61U, 0x7FF38AU, 0x800C75U, 0x80149EU, + 0x80254BU, 0x803DA0U, 0x8046E2U, 0x805E09U, 0x806FDCU, 0x807737U, 0x8081B3U, 0x809958U, 0x80A88DU, 0x80B066U, + 0x80CB24U, 0x80D3CFU, 0x80E21AU, 0x80FAF1U, 0x810F12U, 0x8117F9U, 0x81262CU, 0x813EC7U, 0x814585U, 0x815D6EU, + 0x816CBBU, 0x817450U, 0x8182D4U, 0x819A3FU, 0x81ABEAU, 0x81B301U, 0x81C843U, 0x81D0A8U, 0x81E17DU, 0x81F996U, + 0x820AB8U, 0x821253U, 0x822386U, 0x823B6DU, 0x82402FU, 0x8258C4U, 0x826911U, 0x8271FAU, 0x82877EU, 0x829F95U, + 0x82AE40U, 0x82B6ABU, 0x82CDE9U, 0x82D502U, 0x82E4D7U, 0x82FC3CU, 0x8309DFU, 0x831134U, 0x8320E1U, 0x83380AU, + 0x834348U, 0x835BA3U, 0x836A76U, 0x83729DU, 0x838419U, 0x839CF2U, 0x83AD27U, 0x83B5CCU, 0x83CE8EU, 0x83D665U, + 0x83E7B0U, 0x83FF5BU, 0x8401ECU, 0x841907U, 0x8428D2U, 0x843039U, 0x844B7BU, 0x845390U, 0x846245U, 0x847AAEU, + 0x848C2AU, 0x8494C1U, 0x84A514U, 0x84BDFFU, 0x84C6BDU, 0x84DE56U, 0x84EF83U, 0x84F768U, 0x85028BU, 0x851A60U, + 0x852BB5U, 0x85335EU, 0x85481CU, 0x8550F7U, 0x856122U, 0x8579C9U, 0x858F4DU, 0x8597A6U, 0x85A673U, 0x85BE98U, + 0x85C5DAU, 0x85DD31U, 0x85ECE4U, 0x85F40FU, 0x860721U, 0x861FCAU, 0x862E1FU, 0x8636F4U, 0x864DB6U, 0x86555DU, + 0x866488U, 0x867C63U, 0x868AE7U, 0x86920CU, 0x86A3D9U, 0x86BB32U, 0x86C070U, 0x86D89BU, 0x86E94EU, 0x86F1A5U, + 0x870446U, 0x871CADU, 0x872D78U, 0x873593U, 0x874ED1U, 0x87563AU, 0x8767EFU, 0x877F04U, 0x878980U, 0x87916BU, + 0x87A0BEU, 0x87B855U, 0x87C317U, 0x87DBFCU, 0x87EA29U, 0x87F2C2U, 0x880FAFU, 0x881744U, 0x882691U, 0x883E7AU, + 0x884538U, 0x885DD3U, 0x886C06U, 0x8874EDU, 0x888269U, 0x889A82U, 0x88AB57U, 0x88B3BCU, 0x88C8FEU, 0x88D015U, + 0x88E1C0U, 0x88F92BU, 0x890CC8U, 0x891423U, 0x8925F6U, 0x893D1DU, 0x89465FU, 0x895EB4U, 0x896F61U, 0x89778AU, + 0x89810EU, 0x8999E5U, 0x89A830U, 0x89B0DBU, 0x89CB99U, 0x89D372U, 0x89E2A7U, 0x89FA4CU, 0x8A0962U, 0x8A1189U, + 0x8A205CU, 0x8A38B7U, 0x8A43F5U, 0x8A5B1EU, 0x8A6ACBU, 0x8A7220U, 0x8A84A4U, 0x8A9C4FU, 0x8AAD9AU, 0x8AB571U, + 0x8ACE33U, 0x8AD6D8U, 0x8AE70DU, 0x8AFFE6U, 0x8B0A05U, 0x8B12EEU, 0x8B233BU, 0x8B3BD0U, 0x8B4092U, 0x8B5879U, + 0x8B69ACU, 0x8B7147U, 0x8B87C3U, 0x8B9F28U, 0x8BAEFDU, 0x8BB616U, 0x8BCD54U, 0x8BD5BFU, 0x8BE46AU, 0x8BFC81U, + 0x8C0236U, 0x8C1ADDU, 0x8C2B08U, 0x8C33E3U, 0x8C48A1U, 0x8C504AU, 0x8C619FU, 0x8C7974U, 0x8C8FF0U, 0x8C971BU, + 0x8CA6CEU, 0x8CBE25U, 0x8CC567U, 0x8CDD8CU, 0x8CEC59U, 0x8CF4B2U, 0x8D0151U, 0x8D19BAU, 0x8D286FU, 0x8D3084U, + 0x8D4BC6U, 0x8D532DU, 0x8D62F8U, 0x8D7A13U, 0x8D8C97U, 0x8D947CU, 0x8DA5A9U, 0x8DBD42U, 0x8DC600U, 0x8DDEEBU, + 0x8DEF3EU, 0x8DF7D5U, 0x8E04FBU, 0x8E1C10U, 0x8E2DC5U, 0x8E352EU, 0x8E4E6CU, 0x8E5687U, 0x8E6752U, 0x8E7FB9U, + 0x8E893DU, 0x8E91D6U, 0x8EA003U, 0x8EB8E8U, 0x8EC3AAU, 0x8EDB41U, 0x8EEA94U, 0x8EF27FU, 0x8F079CU, 0x8F1F77U, + 0x8F2EA2U, 0x8F3649U, 0x8F4D0BU, 0x8F55E0U, 0x8F6435U, 0x8F7CDEU, 0x8F8A5AU, 0x8F92B1U, 0x8FA364U, 0x8FBB8FU, + 0x8FC0CDU, 0x8FD826U, 0x8FE9F3U, 0x8FF118U, 0x900BC1U, 0x90132AU, 0x9022FFU, 0x903A14U, 0x904156U, 0x9059BDU, + 0x906868U, 0x907083U, 0x908607U, 0x909EECU, 0x90AF39U, 0x90B7D2U, 0x90CC90U, 0x90D47BU, 0x90E5AEU, 0x90FD45U, + 0x9108A6U, 0x91104DU, 0x912198U, 0x913973U, 0x914231U, 0x915ADAU, 0x916B0FU, 0x9173E4U, 0x918560U, 0x919D8BU, + 0x91AC5EU, 0x91B4B5U, 0x91CFF7U, 0x91D71CU, 0x91E6C9U, 0x91FE22U, 0x920D0CU, 0x9215E7U, 0x922432U, 0x923CD9U, + 0x92479BU, 0x925F70U, 0x926EA5U, 0x92764EU, 0x9280CAU, 0x929821U, 0x92A9F4U, 0x92B11FU, 0x92CA5DU, 0x92D2B6U, + 0x92E363U, 0x92FB88U, 0x930E6BU, 0x931680U, 0x932755U, 0x933FBEU, 0x9344FCU, 0x935C17U, 0x936DC2U, 0x937529U, + 0x9383ADU, 0x939B46U, 0x93AA93U, 0x93B278U, 0x93C93AU, 0x93D1D1U, 0x93E004U, 0x93F8EFU, 0x940658U, 0x941EB3U, + 0x942F66U, 0x94378DU, 0x944CCFU, 0x945424U, 0x9465F1U, 0x947D1AU, 0x948B9EU, 0x949375U, 0x94A2A0U, 0x94BA4BU, + 0x94C109U, 0x94D9E2U, 0x94E837U, 0x94F0DCU, 0x95053FU, 0x951DD4U, 0x952C01U, 0x9534EAU, 0x954FA8U, 0x955743U, + 0x956696U, 0x957E7DU, 0x9588F9U, 0x959012U, 0x95A1C7U, 0x95B92CU, 0x95C26EU, 0x95DA85U, 0x95EB50U, 0x95F3BBU, + 0x960095U, 0x96187EU, 0x9629ABU, 0x963140U, 0x964A02U, 0x9652E9U, 0x96633CU, 0x967BD7U, 0x968D53U, 0x9695B8U, + 0x96A46DU, 0x96BC86U, 0x96C7C4U, 0x96DF2FU, 0x96EEFAU, 0x96F611U, 0x9703F2U, 0x971B19U, 0x972ACCU, 0x973227U, + 0x974965U, 0x97518EU, 0x97605BU, 0x9778B0U, 0x978E34U, 0x9796DFU, 0x97A70AU, 0x97BFE1U, 0x97C4A3U, 0x97DC48U, + 0x97ED9DU, 0x97F576U, 0x98081BU, 0x9810F0U, 0x982125U, 0x9839CEU, 0x98428CU, 0x985A67U, 0x986BB2U, 0x987359U, + 0x9885DDU, 0x989D36U, 0x98ACE3U, 0x98B408U, 0x98CF4AU, 0x98D7A1U, 0x98E674U, 0x98FE9FU, 0x990B7CU, 0x991397U, + 0x992242U, 0x993AA9U, 0x9941EBU, 0x995900U, 0x9968D5U, 0x99703EU, 0x9986BAU, 0x999E51U, 0x99AF84U, 0x99B76FU, + 0x99CC2DU, 0x99D4C6U, 0x99E513U, 0x99FDF8U, 0x9A0ED6U, 0x9A163DU, 0x9A27E8U, 0x9A3F03U, 0x9A4441U, 0x9A5CAAU, + 0x9A6D7FU, 0x9A7594U, 0x9A8310U, 0x9A9BFBU, 0x9AAA2EU, 0x9AB2C5U, 0x9AC987U, 0x9AD16CU, 0x9AE0B9U, 0x9AF852U, + 0x9B0DB1U, 0x9B155AU, 0x9B248FU, 0x9B3C64U, 0x9B4726U, 0x9B5FCDU, 0x9B6E18U, 0x9B76F3U, 0x9B8077U, 0x9B989CU, + 0x9BA949U, 0x9BB1A2U, 0x9BCAE0U, 0x9BD20BU, 0x9BE3DEU, 0x9BFB35U, 0x9C0582U, 0x9C1D69U, 0x9C2CBCU, 0x9C3457U, + 0x9C4F15U, 0x9C57FEU, 0x9C662BU, 0x9C7EC0U, 0x9C8844U, 0x9C90AFU, 0x9CA17AU, 0x9CB991U, 0x9CC2D3U, 0x9CDA38U, + 0x9CEBEDU, 0x9CF306U, 0x9D06E5U, 0x9D1E0EU, 0x9D2FDBU, 0x9D3730U, 0x9D4C72U, 0x9D5499U, 0x9D654CU, 0x9D7DA7U, + 0x9D8B23U, 0x9D93C8U, 0x9DA21DU, 0x9DBAF6U, 0x9DC1B4U, 0x9DD95FU, 0x9DE88AU, 0x9DF061U, 0x9E034FU, 0x9E1BA4U, + 0x9E2A71U, 0x9E329AU, 0x9E49D8U, 0x9E5133U, 0x9E60E6U, 0x9E780DU, 0x9E8E89U, 0x9E9662U, 0x9EA7B7U, 0x9EBF5CU, + 0x9EC41EU, 0x9EDCF5U, 0x9EED20U, 0x9EF5CBU, 0x9F0028U, 0x9F18C3U, 0x9F2916U, 0x9F31FDU, 0x9F4ABFU, 0x9F5254U, + 0x9F6381U, 0x9F7B6AU, 0x9F8DEEU, 0x9F9505U, 0x9FA4D0U, 0x9FBC3BU, 0x9FC779U, 0x9FDF92U, 0x9FEE47U, 0x9FF6ACU, + 0xA0031DU, 0xA01BF6U, 0xA02A23U, 0xA032C8U, 0xA0498AU, 0xA05161U, 0xA060B4U, 0xA0785FU, 0xA08EDBU, 0xA09630U, + 0xA0A7E5U, 0xA0BF0EU, 0xA0C44CU, 0xA0DCA7U, 0xA0ED72U, 0xA0F599U, 0xA1007AU, 0xA11891U, 0xA12944U, 0xA131AFU, + 0xA14AEDU, 0xA15206U, 0xA163D3U, 0xA17B38U, 0xA18DBCU, 0xA19557U, 0xA1A482U, 0xA1BC69U, 0xA1C72BU, 0xA1DFC0U, + 0xA1EE15U, 0xA1F6FEU, 0xA205D0U, 0xA21D3BU, 0xA22CEEU, 0xA23405U, 0xA24F47U, 0xA257ACU, 0xA26679U, 0xA27E92U, + 0xA28816U, 0xA290FDU, 0xA2A128U, 0xA2B9C3U, 0xA2C281U, 0xA2DA6AU, 0xA2EBBFU, 0xA2F354U, 0xA306B7U, 0xA31E5CU, + 0xA32F89U, 0xA33762U, 0xA34C20U, 0xA354CBU, 0xA3651EU, 0xA37DF5U, 0xA38B71U, 0xA3939AU, 0xA3A24FU, 0xA3BAA4U, + 0xA3C1E6U, 0xA3D90DU, 0xA3E8D8U, 0xA3F033U, 0xA40E84U, 0xA4166FU, 0xA427BAU, 0xA43F51U, 0xA44413U, 0xA45CF8U, + 0xA46D2DU, 0xA475C6U, 0xA48342U, 0xA49BA9U, 0xA4AA7CU, 0xA4B297U, 0xA4C9D5U, 0xA4D13EU, 0xA4E0EBU, 0xA4F800U, + 0xA50DE3U, 0xA51508U, 0xA524DDU, 0xA53C36U, 0xA54774U, 0xA55F9FU, 0xA56E4AU, 0xA576A1U, 0xA58025U, 0xA598CEU, + 0xA5A91BU, 0xA5B1F0U, 0xA5CAB2U, 0xA5D259U, 0xA5E38CU, 0xA5FB67U, 0xA60849U, 0xA610A2U, 0xA62177U, 0xA6399CU, + 0xA642DEU, 0xA65A35U, 0xA66BE0U, 0xA6730BU, 0xA6858FU, 0xA69D64U, 0xA6ACB1U, 0xA6B45AU, 0xA6CF18U, 0xA6D7F3U, + 0xA6E626U, 0xA6FECDU, 0xA70B2EU, 0xA713C5U, 0xA72210U, 0xA73AFBU, 0xA741B9U, 0xA75952U, 0xA76887U, 0xA7706CU, + 0xA786E8U, 0xA79E03U, 0xA7AFD6U, 0xA7B73DU, 0xA7CC7FU, 0xA7D494U, 0xA7E541U, 0xA7FDAAU, 0xA800C7U, 0xA8182CU, + 0xA829F9U, 0xA83112U, 0xA84A50U, 0xA852BBU, 0xA8636EU, 0xA87B85U, 0xA88D01U, 0xA895EAU, 0xA8A43FU, 0xA8BCD4U, + 0xA8C796U, 0xA8DF7DU, 0xA8EEA8U, 0xA8F643U, 0xA903A0U, 0xA91B4BU, 0xA92A9EU, 0xA93275U, 0xA94937U, 0xA951DCU, + 0xA96009U, 0xA978E2U, 0xA98E66U, 0xA9968DU, 0xA9A758U, 0xA9BFB3U, 0xA9C4F1U, 0xA9DC1AU, 0xA9EDCFU, 0xA9F524U, + 0xAA060AU, 0xAA1EE1U, 0xAA2F34U, 0xAA37DFU, 0xAA4C9DU, 0xAA5476U, 0xAA65A3U, 0xAA7D48U, 0xAA8BCCU, 0xAA9327U, + 0xAAA2F2U, 0xAABA19U, 0xAAC15BU, 0xAAD9B0U, 0xAAE865U, 0xAAF08EU, 0xAB056DU, 0xAB1D86U, 0xAB2C53U, 0xAB34B8U, + 0xAB4FFAU, 0xAB5711U, 0xAB66C4U, 0xAB7E2FU, 0xAB88ABU, 0xAB9040U, 0xABA195U, 0xABB97EU, 0xABC23CU, 0xABDAD7U, + 0xABEB02U, 0xABF3E9U, 0xAC0D5EU, 0xAC15B5U, 0xAC2460U, 0xAC3C8BU, 0xAC47C9U, 0xAC5F22U, 0xAC6EF7U, 0xAC761CU, + 0xAC8098U, 0xAC9873U, 0xACA9A6U, 0xACB14DU, 0xACCA0FU, 0xACD2E4U, 0xACE331U, 0xACFBDAU, 0xAD0E39U, 0xAD16D2U, + 0xAD2707U, 0xAD3FECU, 0xAD44AEU, 0xAD5C45U, 0xAD6D90U, 0xAD757BU, 0xAD83FFU, 0xAD9B14U, 0xADAAC1U, 0xADB22AU, + 0xADC968U, 0xADD183U, 0xADE056U, 0xADF8BDU, 0xAE0B93U, 0xAE1378U, 0xAE22ADU, 0xAE3A46U, 0xAE4104U, 0xAE59EFU, + 0xAE683AU, 0xAE70D1U, 0xAE8655U, 0xAE9EBEU, 0xAEAF6BU, 0xAEB780U, 0xAECCC2U, 0xAED429U, 0xAEE5FCU, 0xAEFD17U, + 0xAF08F4U, 0xAF101FU, 0xAF21CAU, 0xAF3921U, 0xAF4263U, 0xAF5A88U, 0xAF6B5DU, 0xAF73B6U, 0xAF8532U, 0xAF9DD9U, + 0xAFAC0CU, 0xAFB4E7U, 0xAFCFA5U, 0xAFD74EU, 0xAFE69BU, 0xAFFE70U, 0xB004A9U, 0xB01C42U, 0xB02D97U, 0xB0357CU, + 0xB04E3EU, 0xB056D5U, 0xB06700U, 0xB07FEBU, 0xB0896FU, 0xB09184U, 0xB0A051U, 0xB0B8BAU, 0xB0C3F8U, 0xB0DB13U, + 0xB0EAC6U, 0xB0F22DU, 0xB107CEU, 0xB11F25U, 0xB12EF0U, 0xB1361BU, 0xB14D59U, 0xB155B2U, 0xB16467U, 0xB17C8CU, + 0xB18A08U, 0xB192E3U, 0xB1A336U, 0xB1BBDDU, 0xB1C09FU, 0xB1D874U, 0xB1E9A1U, 0xB1F14AU, 0xB20264U, 0xB21A8FU, + 0xB22B5AU, 0xB233B1U, 0xB248F3U, 0xB25018U, 0xB261CDU, 0xB27926U, 0xB28FA2U, 0xB29749U, 0xB2A69CU, 0xB2BE77U, + 0xB2C535U, 0xB2DDDEU, 0xB2EC0BU, 0xB2F4E0U, 0xB30103U, 0xB319E8U, 0xB3283DU, 0xB330D6U, 0xB34B94U, 0xB3537FU, + 0xB362AAU, 0xB37A41U, 0xB38CC5U, 0xB3942EU, 0xB3A5FBU, 0xB3BD10U, 0xB3C652U, 0xB3DEB9U, 0xB3EF6CU, 0xB3F787U, + 0xB40930U, 0xB411DBU, 0xB4200EU, 0xB438E5U, 0xB443A7U, 0xB45B4CU, 0xB46A99U, 0xB47272U, 0xB484F6U, 0xB49C1DU, + 0xB4ADC8U, 0xB4B523U, 0xB4CE61U, 0xB4D68AU, 0xB4E75FU, 0xB4FFB4U, 0xB50A57U, 0xB512BCU, 0xB52369U, 0xB53B82U, + 0xB540C0U, 0xB5582BU, 0xB569FEU, 0xB57115U, 0xB58791U, 0xB59F7AU, 0xB5AEAFU, 0xB5B644U, 0xB5CD06U, 0xB5D5EDU, + 0xB5E438U, 0xB5FCD3U, 0xB60FFDU, 0xB61716U, 0xB626C3U, 0xB63E28U, 0xB6456AU, 0xB65D81U, 0xB66C54U, 0xB674BFU, + 0xB6823BU, 0xB69AD0U, 0xB6AB05U, 0xB6B3EEU, 0xB6C8ACU, 0xB6D047U, 0xB6E192U, 0xB6F979U, 0xB70C9AU, 0xB71471U, + 0xB725A4U, 0xB73D4FU, 0xB7460DU, 0xB75EE6U, 0xB76F33U, 0xB777D8U, 0xB7815CU, 0xB799B7U, 0xB7A862U, 0xB7B089U, + 0xB7CBCBU, 0xB7D320U, 0xB7E2F5U, 0xB7FA1EU, 0xB80773U, 0xB81F98U, 0xB82E4DU, 0xB836A6U, 0xB84DE4U, 0xB8550FU, + 0xB864DAU, 0xB87C31U, 0xB88AB5U, 0xB8925EU, 0xB8A38BU, 0xB8BB60U, 0xB8C022U, 0xB8D8C9U, 0xB8E91CU, 0xB8F1F7U, + 0xB90414U, 0xB91CFFU, 0xB92D2AU, 0xB935C1U, 0xB94E83U, 0xB95668U, 0xB967BDU, 0xB97F56U, 0xB989D2U, 0xB99139U, + 0xB9A0ECU, 0xB9B807U, 0xB9C345U, 0xB9DBAEU, 0xB9EA7BU, 0xB9F290U, 0xBA01BEU, 0xBA1955U, 0xBA2880U, 0xBA306BU, + 0xBA4B29U, 0xBA53C2U, 0xBA6217U, 0xBA7AFCU, 0xBA8C78U, 0xBA9493U, 0xBAA546U, 0xBABDADU, 0xBAC6EFU, 0xBADE04U, + 0xBAEFD1U, 0xBAF73AU, 0xBB02D9U, 0xBB1A32U, 0xBB2BE7U, 0xBB330CU, 0xBB484EU, 0xBB50A5U, 0xBB6170U, 0xBB799BU, + 0xBB8F1FU, 0xBB97F4U, 0xBBA621U, 0xBBBECAU, 0xBBC588U, 0xBBDD63U, 0xBBECB6U, 0xBBF45DU, 0xBC0AEAU, 0xBC1201U, + 0xBC23D4U, 0xBC3B3FU, 0xBC407DU, 0xBC5896U, 0xBC6943U, 0xBC71A8U, 0xBC872CU, 0xBC9FC7U, 0xBCAE12U, 0xBCB6F9U, + 0xBCCDBBU, 0xBCD550U, 0xBCE485U, 0xBCFC6EU, 0xBD098DU, 0xBD1166U, 0xBD20B3U, 0xBD3858U, 0xBD431AU, 0xBD5BF1U, + 0xBD6A24U, 0xBD72CFU, 0xBD844BU, 0xBD9CA0U, 0xBDAD75U, 0xBDB59EU, 0xBDCEDCU, 0xBDD637U, 0xBDE7E2U, 0xBDFF09U, + 0xBE0C27U, 0xBE14CCU, 0xBE2519U, 0xBE3DF2U, 0xBE46B0U, 0xBE5E5BU, 0xBE6F8EU, 0xBE7765U, 0xBE81E1U, 0xBE990AU, + 0xBEA8DFU, 0xBEB034U, 0xBECB76U, 0xBED39DU, 0xBEE248U, 0xBEFAA3U, 0xBF0F40U, 0xBF17ABU, 0xBF267EU, 0xBF3E95U, + 0xBF45D7U, 0xBF5D3CU, 0xBF6CE9U, 0xBF7402U, 0xBF8286U, 0xBF9A6DU, 0xBFABB8U, 0xBFB353U, 0xBFC811U, 0xBFD0FAU, + 0xBFE12FU, 0xBFF9C4U, 0xC00A4EU, 0xC012A5U, 0xC02370U, 0xC03B9BU, 0xC040D9U, 0xC05832U, 0xC069E7U, 0xC0710CU, + 0xC08788U, 0xC09F63U, 0xC0AEB6U, 0xC0B65DU, 0xC0CD1FU, 0xC0D5F4U, 0xC0E421U, 0xC0FCCAU, 0xC10929U, 0xC111C2U, + 0xC12017U, 0xC138FCU, 0xC143BEU, 0xC15B55U, 0xC16A80U, 0xC1726BU, 0xC184EFU, 0xC19C04U, 0xC1ADD1U, 0xC1B53AU, + 0xC1CE78U, 0xC1D693U, 0xC1E746U, 0xC1FFADU, 0xC20C83U, 0xC21468U, 0xC225BDU, 0xC23D56U, 0xC24614U, 0xC25EFFU, + 0xC26F2AU, 0xC277C1U, 0xC28145U, 0xC299AEU, 0xC2A87BU, 0xC2B090U, 0xC2CBD2U, 0xC2D339U, 0xC2E2ECU, 0xC2FA07U, + 0xC30FE4U, 0xC3170FU, 0xC326DAU, 0xC33E31U, 0xC34573U, 0xC35D98U, 0xC36C4DU, 0xC374A6U, 0xC38222U, 0xC39AC9U, + 0xC3AB1CU, 0xC3B3F7U, 0xC3C8B5U, 0xC3D05EU, 0xC3E18BU, 0xC3F960U, 0xC407D7U, 0xC41F3CU, 0xC42EE9U, 0xC43602U, + 0xC44D40U, 0xC455ABU, 0xC4647EU, 0xC47C95U, 0xC48A11U, 0xC492FAU, 0xC4A32FU, 0xC4BBC4U, 0xC4C086U, 0xC4D86DU, + 0xC4E9B8U, 0xC4F153U, 0xC504B0U, 0xC51C5BU, 0xC52D8EU, 0xC53565U, 0xC54E27U, 0xC556CCU, 0xC56719U, 0xC57FF2U, + 0xC58976U, 0xC5919DU, 0xC5A048U, 0xC5B8A3U, 0xC5C3E1U, 0xC5DB0AU, 0xC5EADFU, 0xC5F234U, 0xC6011AU, 0xC619F1U, + 0xC62824U, 0xC630CFU, 0xC64B8DU, 0xC65366U, 0xC662B3U, 0xC67A58U, 0xC68CDCU, 0xC69437U, 0xC6A5E2U, 0xC6BD09U, + 0xC6C64BU, 0xC6DEA0U, 0xC6EF75U, 0xC6F79EU, 0xC7027DU, 0xC71A96U, 0xC72B43U, 0xC733A8U, 0xC748EAU, 0xC75001U, + 0xC761D4U, 0xC7793FU, 0xC78FBBU, 0xC79750U, 0xC7A685U, 0xC7BE6EU, 0xC7C52CU, 0xC7DDC7U, 0xC7EC12U, 0xC7F4F9U, + 0xC80994U, 0xC8117FU, 0xC820AAU, 0xC83841U, 0xC84303U, 0xC85BE8U, 0xC86A3DU, 0xC872D6U, 0xC88452U, 0xC89CB9U, + 0xC8AD6CU, 0xC8B587U, 0xC8CEC5U, 0xC8D62EU, 0xC8E7FBU, 0xC8FF10U, 0xC90AF3U, 0xC91218U, 0xC923CDU, 0xC93B26U, + 0xC94064U, 0xC9588FU, 0xC9695AU, 0xC971B1U, 0xC98735U, 0xC99FDEU, 0xC9AE0BU, 0xC9B6E0U, 0xC9CDA2U, 0xC9D549U, + 0xC9E49CU, 0xC9FC77U, 0xCA0F59U, 0xCA17B2U, 0xCA2667U, 0xCA3E8CU, 0xCA45CEU, 0xCA5D25U, 0xCA6CF0U, 0xCA741BU, + 0xCA829FU, 0xCA9A74U, 0xCAABA1U, 0xCAB34AU, 0xCAC808U, 0xCAD0E3U, 0xCAE136U, 0xCAF9DDU, 0xCB0C3EU, 0xCB14D5U, + 0xCB2500U, 0xCB3DEBU, 0xCB46A9U, 0xCB5E42U, 0xCB6F97U, 0xCB777CU, 0xCB81F8U, 0xCB9913U, 0xCBA8C6U, 0xCBB02DU, + 0xCBCB6FU, 0xCBD384U, 0xCBE251U, 0xCBFABAU, 0xCC040DU, 0xCC1CE6U, 0xCC2D33U, 0xCC35D8U, 0xCC4E9AU, 0xCC5671U, + 0xCC67A4U, 0xCC7F4FU, 0xCC89CBU, 0xCC9120U, 0xCCA0F5U, 0xCCB81EU, 0xCCC35CU, 0xCCDBB7U, 0xCCEA62U, 0xCCF289U, + 0xCD076AU, 0xCD1F81U, 0xCD2E54U, 0xCD36BFU, 0xCD4DFDU, 0xCD5516U, 0xCD64C3U, 0xCD7C28U, 0xCD8AACU, 0xCD9247U, + 0xCDA392U, 0xCDBB79U, 0xCDC03BU, 0xCDD8D0U, 0xCDE905U, 0xCDF1EEU, 0xCE02C0U, 0xCE1A2BU, 0xCE2BFEU, 0xCE3315U, + 0xCE4857U, 0xCE50BCU, 0xCE6169U, 0xCE7982U, 0xCE8F06U, 0xCE97EDU, 0xCEA638U, 0xCEBED3U, 0xCEC591U, 0xCEDD7AU, + 0xCEECAFU, 0xCEF444U, 0xCF01A7U, 0xCF194CU, 0xCF2899U, 0xCF3072U, 0xCF4B30U, 0xCF53DBU, 0xCF620EU, 0xCF7AE5U, + 0xCF8C61U, 0xCF948AU, 0xCFA55FU, 0xCFBDB4U, 0xCFC6F6U, 0xCFDE1DU, 0xCFEFC8U, 0xCFF723U, 0xD00DFAU, 0xD01511U, + 0xD024C4U, 0xD03C2FU, 0xD0476DU, 0xD05F86U, 0xD06E53U, 0xD076B8U, 0xD0803CU, 0xD098D7U, 0xD0A902U, 0xD0B1E9U, + 0xD0CAABU, 0xD0D240U, 0xD0E395U, 0xD0FB7EU, 0xD10E9DU, 0xD11676U, 0xD127A3U, 0xD13F48U, 0xD1440AU, 0xD15CE1U, + 0xD16D34U, 0xD175DFU, 0xD1835BU, 0xD19BB0U, 0xD1AA65U, 0xD1B28EU, 0xD1C9CCU, 0xD1D127U, 0xD1E0F2U, 0xD1F819U, + 0xD20B37U, 0xD213DCU, 0xD22209U, 0xD23AE2U, 0xD241A0U, 0xD2594BU, 0xD2689EU, 0xD27075U, 0xD286F1U, 0xD29E1AU, + 0xD2AFCFU, 0xD2B724U, 0xD2CC66U, 0xD2D48DU, 0xD2E558U, 0xD2FDB3U, 0xD30850U, 0xD310BBU, 0xD3216EU, 0xD33985U, + 0xD342C7U, 0xD35A2CU, 0xD36BF9U, 0xD37312U, 0xD38596U, 0xD39D7DU, 0xD3ACA8U, 0xD3B443U, 0xD3CF01U, 0xD3D7EAU, + 0xD3E63FU, 0xD3FED4U, 0xD40063U, 0xD41888U, 0xD4295DU, 0xD431B6U, 0xD44AF4U, 0xD4521FU, 0xD463CAU, 0xD47B21U, + 0xD48DA5U, 0xD4954EU, 0xD4A49BU, 0xD4BC70U, 0xD4C732U, 0xD4DFD9U, 0xD4EE0CU, 0xD4F6E7U, 0xD50304U, 0xD51BEFU, + 0xD52A3AU, 0xD532D1U, 0xD54993U, 0xD55178U, 0xD560ADU, 0xD57846U, 0xD58EC2U, 0xD59629U, 0xD5A7FCU, 0xD5BF17U, + 0xD5C455U, 0xD5DCBEU, 0xD5ED6BU, 0xD5F580U, 0xD606AEU, 0xD61E45U, 0xD62F90U, 0xD6377BU, 0xD64C39U, 0xD654D2U, + 0xD66507U, 0xD67DECU, 0xD68B68U, 0xD69383U, 0xD6A256U, 0xD6BABDU, 0xD6C1FFU, 0xD6D914U, 0xD6E8C1U, 0xD6F02AU, + 0xD705C9U, 0xD71D22U, 0xD72CF7U, 0xD7341CU, 0xD74F5EU, 0xD757B5U, 0xD76660U, 0xD77E8BU, 0xD7880FU, 0xD790E4U, + 0xD7A131U, 0xD7B9DAU, 0xD7C298U, 0xD7DA73U, 0xD7EBA6U, 0xD7F34DU, 0xD80E20U, 0xD816CBU, 0xD8271EU, 0xD83FF5U, + 0xD844B7U, 0xD85C5CU, 0xD86D89U, 0xD87562U, 0xD883E6U, 0xD89B0DU, 0xD8AAD8U, 0xD8B233U, 0xD8C971U, 0xD8D19AU, + 0xD8E04FU, 0xD8F8A4U, 0xD90D47U, 0xD915ACU, 0xD92479U, 0xD93C92U, 0xD947D0U, 0xD95F3BU, 0xD96EEEU, 0xD97605U, + 0xD98081U, 0xD9986AU, 0xD9A9BFU, 0xD9B154U, 0xD9CA16U, 0xD9D2FDU, 0xD9E328U, 0xD9FBC3U, 0xDA08EDU, 0xDA1006U, + 0xDA21D3U, 0xDA3938U, 0xDA427AU, 0xDA5A91U, 0xDA6B44U, 0xDA73AFU, 0xDA852BU, 0xDA9DC0U, 0xDAAC15U, 0xDAB4FEU, + 0xDACFBCU, 0xDAD757U, 0xDAE682U, 0xDAFE69U, 0xDB0B8AU, 0xDB1361U, 0xDB22B4U, 0xDB3A5FU, 0xDB411DU, 0xDB59F6U, + 0xDB6823U, 0xDB70C8U, 0xDB864CU, 0xDB9EA7U, 0xDBAF72U, 0xDBB799U, 0xDBCCDBU, 0xDBD430U, 0xDBE5E5U, 0xDBFD0EU, + 0xDC03B9U, 0xDC1B52U, 0xDC2A87U, 0xDC326CU, 0xDC492EU, 0xDC51C5U, 0xDC6010U, 0xDC78FBU, 0xDC8E7FU, 0xDC9694U, + 0xDCA741U, 0xDCBFAAU, 0xDCC4E8U, 0xDCDC03U, 0xDCEDD6U, 0xDCF53DU, 0xDD00DEU, 0xDD1835U, 0xDD29E0U, 0xDD310BU, + 0xDD4A49U, 0xDD52A2U, 0xDD6377U, 0xDD7B9CU, 0xDD8D18U, 0xDD95F3U, 0xDDA426U, 0xDDBCCDU, 0xDDC78FU, 0xDDDF64U, + 0xDDEEB1U, 0xDDF65AU, 0xDE0574U, 0xDE1D9FU, 0xDE2C4AU, 0xDE34A1U, 0xDE4FE3U, 0xDE5708U, 0xDE66DDU, 0xDE7E36U, + 0xDE88B2U, 0xDE9059U, 0xDEA18CU, 0xDEB967U, 0xDEC225U, 0xDEDACEU, 0xDEEB1BU, 0xDEF3F0U, 0xDF0613U, 0xDF1EF8U, + 0xDF2F2DU, 0xDF37C6U, 0xDF4C84U, 0xDF546FU, 0xDF65BAU, 0xDF7D51U, 0xDF8BD5U, 0xDF933EU, 0xDFA2EBU, 0xDFBA00U, + 0xDFC142U, 0xDFD9A9U, 0xDFE87CU, 0xDFF097U, 0xE00526U, 0xE01DCDU, 0xE02C18U, 0xE034F3U, 0xE04FB1U, 0xE0575AU, + 0xE0668FU, 0xE07E64U, 0xE088E0U, 0xE0900BU, 0xE0A1DEU, 0xE0B935U, 0xE0C277U, 0xE0DA9CU, 0xE0EB49U, 0xE0F3A2U, + 0xE10641U, 0xE11EAAU, 0xE12F7FU, 0xE13794U, 0xE14CD6U, 0xE1543DU, 0xE165E8U, 0xE17D03U, 0xE18B87U, 0xE1936CU, + 0xE1A2B9U, 0xE1BA52U, 0xE1C110U, 0xE1D9FBU, 0xE1E82EU, 0xE1F0C5U, 0xE203EBU, 0xE21B00U, 0xE22AD5U, 0xE2323EU, + 0xE2497CU, 0xE25197U, 0xE26042U, 0xE278A9U, 0xE28E2DU, 0xE296C6U, 0xE2A713U, 0xE2BFF8U, 0xE2C4BAU, 0xE2DC51U, + 0xE2ED84U, 0xE2F56FU, 0xE3008CU, 0xE31867U, 0xE329B2U, 0xE33159U, 0xE34A1BU, 0xE352F0U, 0xE36325U, 0xE37BCEU, + 0xE38D4AU, 0xE395A1U, 0xE3A474U, 0xE3BC9FU, 0xE3C7DDU, 0xE3DF36U, 0xE3EEE3U, 0xE3F608U, 0xE408BFU, 0xE41054U, + 0xE42181U, 0xE4396AU, 0xE44228U, 0xE45AC3U, 0xE46B16U, 0xE473FDU, 0xE48579U, 0xE49D92U, 0xE4AC47U, 0xE4B4ACU, + 0xE4CFEEU, 0xE4D705U, 0xE4E6D0U, 0xE4FE3BU, 0xE50BD8U, 0xE51333U, 0xE522E6U, 0xE53A0DU, 0xE5414FU, 0xE559A4U, + 0xE56871U, 0xE5709AU, 0xE5861EU, 0xE59EF5U, 0xE5AF20U, 0xE5B7CBU, 0xE5CC89U, 0xE5D462U, 0xE5E5B7U, 0xE5FD5CU, + 0xE60E72U, 0xE61699U, 0xE6274CU, 0xE63FA7U, 0xE644E5U, 0xE65C0EU, 0xE66DDBU, 0xE67530U, 0xE683B4U, 0xE69B5FU, + 0xE6AA8AU, 0xE6B261U, 0xE6C923U, 0xE6D1C8U, 0xE6E01DU, 0xE6F8F6U, 0xE70D15U, 0xE715FEU, 0xE7242BU, 0xE73CC0U, + 0xE74782U, 0xE75F69U, 0xE76EBCU, 0xE77657U, 0xE780D3U, 0xE79838U, 0xE7A9EDU, 0xE7B106U, 0xE7CA44U, 0xE7D2AFU, + 0xE7E37AU, 0xE7FB91U, 0xE806FCU, 0xE81E17U, 0xE82FC2U, 0xE83729U, 0xE84C6BU, 0xE85480U, 0xE86555U, 0xE87DBEU, + 0xE88B3AU, 0xE893D1U, 0xE8A204U, 0xE8BAEFU, 0xE8C1ADU, 0xE8D946U, 0xE8E893U, 0xE8F078U, 0xE9059BU, 0xE91D70U, + 0xE92CA5U, 0xE9344EU, 0xE94F0CU, 0xE957E7U, 0xE96632U, 0xE97ED9U, 0xE9885DU, 0xE990B6U, 0xE9A163U, 0xE9B988U, + 0xE9C2CAU, 0xE9DA21U, 0xE9EBF4U, 0xE9F31FU, 0xEA0031U, 0xEA18DAU, 0xEA290FU, 0xEA31E4U, 0xEA4AA6U, 0xEA524DU, + 0xEA6398U, 0xEA7B73U, 0xEA8DF7U, 0xEA951CU, 0xEAA4C9U, 0xEABC22U, 0xEAC760U, 0xEADF8BU, 0xEAEE5EU, 0xEAF6B5U, + 0xEB0356U, 0xEB1BBDU, 0xEB2A68U, 0xEB3283U, 0xEB49C1U, 0xEB512AU, 0xEB60FFU, 0xEB7814U, 0xEB8E90U, 0xEB967BU, + 0xEBA7AEU, 0xEBBF45U, 0xEBC407U, 0xEBDCECU, 0xEBED39U, 0xEBF5D2U, 0xEC0B65U, 0xEC138EU, 0xEC225BU, 0xEC3AB0U, + 0xEC41F2U, 0xEC5919U, 0xEC68CCU, 0xEC7027U, 0xEC86A3U, 0xEC9E48U, 0xECAF9DU, 0xECB776U, 0xECCC34U, 0xECD4DFU, + 0xECE50AU, 0xECFDE1U, 0xED0802U, 0xED10E9U, 0xED213CU, 0xED39D7U, 0xED4295U, 0xED5A7EU, 0xED6BABU, 0xED7340U, + 0xED85C4U, 0xED9D2FU, 0xEDACFAU, 0xEDB411U, 0xEDCF53U, 0xEDD7B8U, 0xEDE66DU, 0xEDFE86U, 0xEE0DA8U, 0xEE1543U, + 0xEE2496U, 0xEE3C7DU, 0xEE473FU, 0xEE5FD4U, 0xEE6E01U, 0xEE76EAU, 0xEE806EU, 0xEE9885U, 0xEEA950U, 0xEEB1BBU, + 0xEECAF9U, 0xEED212U, 0xEEE3C7U, 0xEEFB2CU, 0xEF0ECFU, 0xEF1624U, 0xEF27F1U, 0xEF3F1AU, 0xEF4458U, 0xEF5CB3U, + 0xEF6D66U, 0xEF758DU, 0xEF8309U, 0xEF9BE2U, 0xEFAA37U, 0xEFB2DCU, 0xEFC99EU, 0xEFD175U, 0xEFE0A0U, 0xEFF84BU, + 0xF00292U, 0xF01A79U, 0xF02BACU, 0xF03347U, 0xF04805U, 0xF050EEU, 0xF0613BU, 0xF079D0U, 0xF08F54U, 0xF097BFU, + 0xF0A66AU, 0xF0BE81U, 0xF0C5C3U, 0xF0DD28U, 0xF0ECFDU, 0xF0F416U, 0xF101F5U, 0xF1191EU, 0xF128CBU, 0xF13020U, + 0xF14B62U, 0xF15389U, 0xF1625CU, 0xF17AB7U, 0xF18C33U, 0xF194D8U, 0xF1A50DU, 0xF1BDE6U, 0xF1C6A4U, 0xF1DE4FU, + 0xF1EF9AU, 0xF1F771U, 0xF2045FU, 0xF21CB4U, 0xF22D61U, 0xF2358AU, 0xF24EC8U, 0xF25623U, 0xF267F6U, 0xF27F1DU, + 0xF28999U, 0xF29172U, 0xF2A0A7U, 0xF2B84CU, 0xF2C30EU, 0xF2DBE5U, 0xF2EA30U, 0xF2F2DBU, 0xF30738U, 0xF31FD3U, + 0xF32E06U, 0xF336EDU, 0xF34DAFU, 0xF35544U, 0xF36491U, 0xF37C7AU, 0xF38AFEU, 0xF39215U, 0xF3A3C0U, 0xF3BB2BU, + 0xF3C069U, 0xF3D882U, 0xF3E957U, 0xF3F1BCU, 0xF40F0BU, 0xF417E0U, 0xF42635U, 0xF43EDEU, 0xF4459CU, 0xF45D77U, + 0xF46CA2U, 0xF47449U, 0xF482CDU, 0xF49A26U, 0xF4ABF3U, 0xF4B318U, 0xF4C85AU, 0xF4D0B1U, 0xF4E164U, 0xF4F98FU, + 0xF50C6CU, 0xF51487U, 0xF52552U, 0xF53DB9U, 0xF546FBU, 0xF55E10U, 0xF56FC5U, 0xF5772EU, 0xF581AAU, 0xF59941U, + 0xF5A894U, 0xF5B07FU, 0xF5CB3DU, 0xF5D3D6U, 0xF5E203U, 0xF5FAE8U, 0xF609C6U, 0xF6112DU, 0xF620F8U, 0xF63813U, + 0xF64351U, 0xF65BBAU, 0xF66A6FU, 0xF67284U, 0xF68400U, 0xF69CEBU, 0xF6AD3EU, 0xF6B5D5U, 0xF6CE97U, 0xF6D67CU, + 0xF6E7A9U, 0xF6FF42U, 0xF70AA1U, 0xF7124AU, 0xF7239FU, 0xF73B74U, 0xF74036U, 0xF758DDU, 0xF76908U, 0xF771E3U, + 0xF78767U, 0xF79F8CU, 0xF7AE59U, 0xF7B6B2U, 0xF7CDF0U, 0xF7D51BU, 0xF7E4CEU, 0xF7FC25U, 0xF80148U, 0xF819A3U, + 0xF82876U, 0xF8309DU, 0xF84BDFU, 0xF85334U, 0xF862E1U, 0xF87A0AU, 0xF88C8EU, 0xF89465U, 0xF8A5B0U, 0xF8BD5BU, + 0xF8C619U, 0xF8DEF2U, 0xF8EF27U, 0xF8F7CCU, 0xF9022FU, 0xF91AC4U, 0xF92B11U, 0xF933FAU, 0xF948B8U, 0xF95053U, + 0xF96186U, 0xF9796DU, 0xF98FE9U, 0xF99702U, 0xF9A6D7U, 0xF9BE3CU, 0xF9C57EU, 0xF9DD95U, 0xF9EC40U, 0xF9F4ABU, + 0xFA0785U, 0xFA1F6EU, 0xFA2EBBU, 0xFA3650U, 0xFA4D12U, 0xFA55F9U, 0xFA642CU, 0xFA7CC7U, 0xFA8A43U, 0xFA92A8U, + 0xFAA37DU, 0xFABB96U, 0xFAC0D4U, 0xFAD83FU, 0xFAE9EAU, 0xFAF101U, 0xFB04E2U, 0xFB1C09U, 0xFB2DDCU, 0xFB3537U, + 0xFB4E75U, 0xFB569EU, 0xFB674BU, 0xFB7FA0U, 0xFB8924U, 0xFB91CFU, 0xFBA01AU, 0xFBB8F1U, 0xFBC3B3U, 0xFBDB58U, + 0xFBEA8DU, 0xFBF266U, 0xFC0CD1U, 0xFC143AU, 0xFC25EFU, 0xFC3D04U, 0xFC4646U, 0xFC5EADU, 0xFC6F78U, 0xFC7793U, + 0xFC8117U, 0xFC99FCU, 0xFCA829U, 0xFCB0C2U, 0xFCCB80U, 0xFCD36BU, 0xFCE2BEU, 0xFCFA55U, 0xFD0FB6U, 0xFD175DU, + 0xFD2688U, 0xFD3E63U, 0xFD4521U, 0xFD5DCAU, 0xFD6C1FU, 0xFD74F4U, 0xFD8270U, 0xFD9A9BU, 0xFDAB4EU, 0xFDB3A5U, + 0xFDC8E7U, 0xFDD00CU, 0xFDE1D9U, 0xFDF932U, 0xFE0A1CU, 0xFE12F7U, 0xFE2322U, 0xFE3BC9U, 0xFE408BU, 0xFE5860U, + 0xFE69B5U, 0xFE715EU, 0xFE87DAU, 0xFE9F31U, 0xFEAEE4U, 0xFEB60FU, 0xFECD4DU, 0xFED5A6U, 0xFEE473U, 0xFEFC98U, + 0xFF097BU, 0xFF1190U, 0xFF2045U, 0xFF38AEU, 0xFF43ECU, 0xFF5B07U, 0xFF6AD2U, 0xFF7239U, 0xFF84BDU, 0xFF9C56U, + 0xFFAD83U, 0xFFB568U, 0xFFCE2AU, 0xFFD6C1U, 0xFFE714U, 0xFFFFFFU }; + +static const uint32_t DECODING_TABLE_23127[] = { + 0x000000U, 0x000001U, 0x000002U, 0x000003U, 0x000004U, 0x000005U, 0x000006U, 0x000007U, 0x000008U, 0x000009U, + 0x00000AU, 0x00000BU, 0x00000CU, 0x00000DU, 0x00000EU, 0x024020U, 0x000010U, 0x000011U, 0x000012U, 0x000013U, + 0x000014U, 0x000015U, 0x000016U, 0x412000U, 0x000018U, 0x000019U, 0x00001AU, 0x180800U, 0x00001CU, 0x200300U, + 0x048040U, 0x001480U, 0x000020U, 0x000021U, 0x000022U, 0x000023U, 0x000024U, 0x000025U, 0x000026U, 0x024008U, + 0x000028U, 0x000029U, 0x00002AU, 0x024004U, 0x00002CU, 0x024002U, 0x024001U, 0x024000U, 0x000030U, 0x000031U, + 0x000032U, 0x008180U, 0x000034U, 0x000C40U, 0x301000U, 0x0C0200U, 0x000038U, 0x043000U, 0x400600U, 0x210040U, + 0x090080U, 0x508000U, 0x002900U, 0x024010U, 0x000040U, 0x000041U, 0x000042U, 0x000043U, 0x000044U, 0x000045U, + 0x000046U, 0x280080U, 0x000048U, 0x000049U, 0x00004AU, 0x002500U, 0x00004CU, 0x111000U, 0x048010U, 0x400A00U, + 0x000050U, 0x000051U, 0x000052U, 0x021200U, 0x000054U, 0x000C20U, 0x048008U, 0x104100U, 0x000058U, 0x404080U, + 0x048004U, 0x210020U, 0x048002U, 0x0A2000U, 0x048000U, 0x048001U, 0x000060U, 0x000061U, 0x000062U, 0x540000U, + 0x000064U, 0x000C10U, 0x010300U, 0x00B000U, 0x000068U, 0x088200U, 0x001880U, 0x210010U, 0x602000U, 0x040180U, + 0x180400U, 0x024040U, 0x000070U, 0x000C04U, 0x086000U, 0x210008U, 0x000C01U, 0x000C00U, 0x420080U, 0x000C02U, + 0x120100U, 0x210002U, 0x210001U, 0x210000U, 0x005200U, 0x000C08U, 0x048020U, 0x210004U, 0x000080U, 0x000081U, + 0x000082U, 0x000083U, 0x000084U, 0x000085U, 0x000086U, 0x280040U, 0x000088U, 0x000089U, 0x00008AU, 0x050200U, + 0x00008CU, 0x00A800U, 0x500100U, 0x001410U, 0x000090U, 0x000091U, 0x000092U, 0x008120U, 0x000094U, 0x160000U, + 0x004A00U, 0x001408U, 0x000098U, 0x404040U, 0x222000U, 0x001404U, 0x090020U, 0x001402U, 0x001401U, 0x001400U, + 0x0000A0U, 0x0000A1U, 0x0000A2U, 0x008110U, 0x0000A4U, 0x401200U, 0x042400U, 0x110800U, 0x0000A8U, 0x300400U, + 0x001840U, 0x482000U, 0x090010U, 0x040140U, 0x208200U, 0x024080U, 0x0000B0U, 0x008102U, 0x008101U, 0x008100U, + 0x090008U, 0x206000U, 0x420040U, 0x008104U, 0x090004U, 0x020A00U, 0x144000U, 0x008108U, 0x090000U, 0x090001U, + 0x090002U, 0x001420U, 0x0000C0U, 0x0000C1U, 0x0000C2U, 0x280004U, 0x0000C4U, 0x280002U, 0x280001U, 0x280000U, + 0x0000C8U, 0x404010U, 0x001820U, 0x128000U, 0x020600U, 0x040120U, 0x016000U, 0x280008U, 0x0000D0U, 0x404008U, + 0x110400U, 0x042800U, 0x003100U, 0x018200U, 0x420020U, 0x280010U, 0x404001U, 0x404000U, 0x080300U, 0x404002U, + 0x300800U, 0x404004U, 0x048080U, 0x001440U, 0x0000E0U, 0x032000U, 0x001808U, 0x004600U, 0x10C000U, 0x040108U, + 0x420010U, 0x280020U, 0x001802U, 0x040104U, 0x001800U, 0x001801U, 0x040101U, 0x040100U, 0x001804U, 0x040102U, + 0x240200U, 0x181000U, 0x420004U, 0x008140U, 0x420002U, 0x000C80U, 0x420000U, 0x420001U, 0x00A400U, 0x404020U, + 0x001810U, 0x210080U, 0x090040U, 0x040110U, 0x420008U, 0x102200U, 0x000100U, 0x000101U, 0x000102U, 0x000103U, + 0x000104U, 0x000105U, 0x000106U, 0x041800U, 0x000108U, 0x000109U, 0x00010AU, 0x002440U, 0x00010CU, 0x200210U, + 0x500080U, 0x098000U, 0x000110U, 0x000111U, 0x000112U, 0x0080A0U, 0x000114U, 0x200208U, 0x0A0400U, 0x104040U, + 0x000118U, 0x200204U, 0x015000U, 0x460000U, 0x200201U, 0x200200U, 0x002820U, 0x200202U, 0x000120U, 0x000121U, + 0x000122U, 0x008090U, 0x000124U, 0x182000U, 0x010240U, 0x600400U, 0x000128U, 0x410800U, 0x2C0000U, 0x101200U, + 0x009400U, 0x0400C0U, 0x002810U, 0x024100U, 0x000130U, 0x008082U, 0x008081U, 0x008080U, 0x444000U, 0x031000U, + 0x002808U, 0x008084U, 0x120040U, 0x084400U, 0x002804U, 0x008088U, 0x002802U, 0x200220U, 0x002800U, 0x002801U, + 0x000140U, 0x000141U, 0x000142U, 0x002408U, 0x000144U, 0x428000U, 0x010220U, 0x104010U, 0x000148U, 0x002402U, + 0x002401U, 0x002400U, 0x084800U, 0x0400A0U, 0x221000U, 0x002404U, 0x000150U, 0x0D0000U, 0x600800U, 0x104004U, + 0x003080U, 0x104002U, 0x104001U, 0x104000U, 0x120020U, 0x009800U, 0x080280U, 0x002410U, 0x410400U, 0x200240U, + 0x048100U, 0x104008U, 0x000160U, 0x205000U, 0x010204U, 0x0A0800U, 0x010202U, 0x040088U, 0x010200U, 0x010201U, + 0x120010U, 0x040084U, 0x40C000U, 0x002420U, 0x040081U, 0x040080U, 0x010208U, 0x040082U, 0x120008U, 0x402200U, + 0x041400U, 0x0080C0U, 0x288000U, 0x000D00U, 0x010210U, 0x104020U, 0x120000U, 0x120001U, 0x120002U, 0x210100U, + 0x120004U, 0x040090U, 0x002840U, 0x481000U, 0x000180U, 0x000181U, 0x000182U, 0x008030U, 0x000184U, 0x014400U, + 0x500008U, 0x022200U, 0x000188U, 0x0A1000U, 0x500004U, 0x204800U, 0x500002U, 0x040060U, 0x500000U, 0x500001U, + 0x000190U, 0x008022U, 0x008021U, 0x008020U, 0x003040U, 0x480800U, 0x250000U, 0x008024U, 0x040C00U, 0x112000U, + 0x080240U, 0x008028U, 0x02C000U, 0x200280U, 0x500010U, 0x001500U, 0x0001A0U, 0x008012U, 0x008011U, 0x008010U, + 0x220800U, 0x040048U, 0x085000U, 0x008014U, 0x006200U, 0x040044U, 0x030400U, 0x008018U, 0x040041U, 0x040040U, + 0x500020U, 0x040042U, 0x008003U, 0x008002U, 0x008001U, 0x008000U, 0x100600U, 0x008006U, 0x008005U, 0x008004U, + 0x601000U, 0x00800AU, 0x008009U, 0x008008U, 0x090100U, 0x040050U, 0x002880U, 0x00800CU, 0x0001C0U, 0x100A00U, + 0x064000U, 0x411000U, 0x003010U, 0x040028U, 0x008C00U, 0x280100U, 0x218000U, 0x040024U, 0x080210U, 0x002480U, + 0x040021U, 0x040020U, 0x500040U, 0x040022U, 0x003004U, 0x220400U, 0x080208U, 0x008060U, 0x003000U, 0x003001U, + 0x003002U, 0x104080U, 0x080202U, 0x404100U, 0x080200U, 0x080201U, 0x003008U, 0x040030U, 0x080204U, 0x030800U, + 0x480400U, 0x04000CU, 0x302000U, 0x008050U, 0x040009U, 0x040008U, 0x010280U, 0x04000AU, 0x040005U, 0x040004U, + 0x001900U, 0x040006U, 0x040001U, 0x040000U, 0x040003U, 0x040002U, 0x014800U, 0x008042U, 0x008041U, 0x008040U, + 0x003020U, 0x040018U, 0x420100U, 0x008044U, 0x120080U, 0x040014U, 0x080220U, 0x008048U, 0x040011U, 0x040010U, + 0x204400U, 0x040012U, 0x000200U, 0x000201U, 0x000202U, 0x000203U, 0x000204U, 0x000205U, 0x000206U, 0x108400U, + 0x000208U, 0x000209U, 0x00020AU, 0x050080U, 0x00020CU, 0x200110U, 0x083000U, 0x400840U, 0x000210U, 0x000211U, + 0x000212U, 0x021040U, 0x000214U, 0x200108U, 0x004880U, 0x0C0020U, 0x000218U, 0x200104U, 0x400420U, 0x00E000U, + 0x200101U, 0x200100U, 0x130000U, 0x200102U, 0x000220U, 0x000221U, 0x000222U, 0x202800U, 0x000224U, 0x401080U, + 0x010140U, 0x0C0010U, 0x000228U, 0x088040U, 0x400410U, 0x101100U, 0x140800U, 0x012400U, 0x208080U, 0x024200U, + 0x000230U, 0x114000U, 0x400408U, 0x0C0004U, 0x02A000U, 0x0C0002U, 0x0C0001U, 0x0C0000U, 0x400402U, 0x020880U, + 0x400400U, 0x400401U, 0x005040U, 0x200120U, 0x400404U, 0x0C0008U, 0x000240U, 0x000241U, 0x000242U, 0x021010U, + 0x000244U, 0x046000U, 0x010120U, 0x400808U, 0x000248U, 0x088020U, 0x304000U, 0x400804U, 0x020480U, 0x400802U, + 0x400801U, 0x400800U, 0x000250U, 0x021002U, 0x021001U, 0x021000U, 0x580000U, 0x018080U, 0x202400U, 0x021004U, + 0x012800U, 0x140400U, 0x080180U, 0x021008U, 0x005020U, 0x200140U, 0x048200U, 0x400810U, 0x000260U, 0x088008U, + 0x010104U, 0x004480U, 0x010102U, 0x320000U, 0x010100U, 0x010101U, 0x088001U, 0x088000U, 0x062000U, 0x088002U, + 0x005010U, 0x088004U, 0x010108U, 0x400820U, 0x240080U, 0x402100U, 0x108800U, 0x021020U, 0x005008U, 0x000E00U, + 0x010110U, 0x0C0040U, 0x005004U, 0x088010U, 0x400440U, 0x210200U, 0x005000U, 0x005001U, 0x005002U, 0x102080U, + 0x000280U, 0x000281U, 0x000282U, 0x050008U, 0x000284U, 0x401020U, 0x004810U, 0x022100U, 0x000288U, 0x050002U, + 0x050001U, 0x050000U, 0x020440U, 0x184000U, 0x208020U, 0x050004U, 0x000290U, 0x082400U, 0x004804U, 0x700000U, + 0x004802U, 0x018040U, 0x004800U, 0x004801U, 0x109000U, 0x020820U, 0x080140U, 0x050010U, 0x442000U, 0x200180U, + 0x004808U, 0x001600U, 0x0002A0U, 0x401004U, 0x1A0000U, 0x004440U, 0x401001U, 0x401000U, 0x208008U, 0x401002U, + 0x006100U, 0x020810U, 0x208004U, 0x050020U, 0x208002U, 0x401008U, 0x208000U, 0x208001U, 0x240040U, 0x020808U, + 0x013000U, 0x008300U, 0x100500U, 0x401010U, 0x004820U, 0x0C0080U, 0x020801U, 0x020800U, 0x400480U, 0x020802U, + 0x090200U, 0x020804U, 0x208010U, 0x102040U, 0x0002C0U, 0x100900U, 0x40A000U, 0x004420U, 0x020408U, 0x018010U, + 0x141000U, 0x280200U, 0x020404U, 0x203000U, 0x080110U, 0x050040U, 0x020400U, 0x020401U, 0x020402U, 0x400880U, + 0x240020U, 0x018004U, 0x080108U, 0x021080U, 0x018001U, 0x018000U, 0x004840U, 0x018002U, 0x080102U, 0x404200U, + 0x080100U, 0x080101U, 0x020410U, 0x018008U, 0x080104U, 0x102020U, 0x240010U, 0x004402U, 0x004401U, 0x004400U, + 0x082800U, 0x401040U, 0x010180U, 0x004404U, 0x510000U, 0x088080U, 0x001A00U, 0x004408U, 0x020420U, 0x040300U, + 0x208040U, 0x102010U, 0x240000U, 0x240001U, 0x240002U, 0x004410U, 0x240004U, 0x018020U, 0x420200U, 0x102008U, + 0x240008U, 0x020840U, 0x080120U, 0x102004U, 0x005080U, 0x102002U, 0x102001U, 0x102000U, 0x000300U, 0x000301U, + 0x000302U, 0x484000U, 0x000304U, 0x200018U, 0x010060U, 0x022080U, 0x000308U, 0x200014U, 0x028800U, 0x101020U, + 0x200011U, 0x200010U, 0x044400U, 0x200012U, 0x000310U, 0x20000CU, 0x142000U, 0x010C00U, 0x200009U, 0x200008U, + 0x409000U, 0x20000AU, 0x200005U, 0x200004U, 0x0800C0U, 0x200006U, 0x200001U, 0x200000U, 0x200003U, 0x200002U, + 0x000320U, 0x060400U, 0x010044U, 0x101008U, 0x010042U, 0x00C800U, 0x010040U, 0x010041U, 0x006080U, 0x101002U, + 0x101001U, 0x101000U, 0x4A0000U, 0x200030U, 0x010048U, 0x101004U, 0x081800U, 0x402040U, 0x224000U, 0x008280U, + 0x100480U, 0x200028U, 0x010050U, 0x0C0100U, 0x058000U, 0x200024U, 0x400500U, 0x101010U, 0x200021U, 0x200020U, + 0x002A00U, 0x200022U, 0x000340U, 0x100880U, 0x010024U, 0x248000U, 0x010022U, 0x081400U, 0x010020U, 0x010021U, + 0x441000U, 0x034000U, 0x080090U, 0x002600U, 0x10A000U, 0x200050U, 0x010028U, 0x400900U, 0x00C400U, 0x402020U, + 0x080088U, 0x021100U, 0x060800U, 0x200048U, 0x010030U, 0x104200U, 0x080082U, 0x200044U, 0x080080U, 0x080081U, + 0x200041U, 0x200040U, 0x080084U, 0x200042U, 0x010006U, 0x402010U, 0x010004U, 0x010005U, 0x010002U, 0x010003U, + 0x010000U, 0x010001U, 0x200C00U, 0x088100U, 0x01000CU, 0x101040U, 0x01000AU, 0x040280U, 0x010008U, 0x010009U, + 0x402001U, 0x402000U, 0x010014U, 0x402002U, 0x010012U, 0x402004U, 0x010010U, 0x010011U, 0x120200U, 0x402008U, + 0x0800A0U, 0x044800U, 0x005100U, 0x200060U, 0x010018U, 0x028400U, 0x000380U, 0x100840U, 0x201400U, 0x022004U, + 0x0C8000U, 0x022002U, 0x022001U, 0x022000U, 0x006020U, 0x408400U, 0x080050U, 0x050100U, 0x011800U, 0x200090U, + 0x500200U, 0x022008U, 0x430000U, 0x045000U, 0x080048U, 0x008220U, 0x100420U, 0x200088U, 0x004900U, 0x022010U, + 0x080042U, 0x200084U, 0x080040U, 0x080041U, 0x200081U, 0x200080U, 0x080044U, 0x200082U, 0x006008U, 0x290000U, + 0x440800U, 0x008210U, 0x100410U, 0x401100U, 0x0100C0U, 0x022020U, 0x006000U, 0x006001U, 0x006002U, 0x101080U, + 0x006004U, 0x040240U, 0x208100U, 0x080C00U, 0x100404U, 0x008202U, 0x008201U, 0x008200U, 0x100400U, 0x100401U, + 0x100402U, 0x008204U, 0x006010U, 0x020900U, 0x080060U, 0x008208U, 0x100408U, 0x2000A0U, 0x061000U, 0x414000U, + 0x100801U, 0x100800U, 0x080018U, 0x100802U, 0x604000U, 0x100804U, 0x0100A0U, 0x022040U, 0x080012U, 0x100808U, + 0x080010U, 0x080011U, 0x020500U, 0x040220U, 0x080014U, 0x00D000U, 0x08000AU, 0x100810U, 0x080008U, 0x080009U, + 0x003200U, 0x018100U, 0x08000CU, 0x440400U, 0x080002U, 0x080003U, 0x080000U, 0x080001U, 0x080006U, 0x2000C0U, + 0x080004U, 0x080005U, 0x029000U, 0x100820U, 0x010084U, 0x004500U, 0x010082U, 0x040208U, 0x010080U, 0x010081U, + 0x006040U, 0x040204U, 0x080030U, 0x620000U, 0x040201U, 0x040200U, 0x010088U, 0x040202U, 0x240100U, 0x402080U, + 0x080028U, 0x008240U, 0x100440U, 0x0A4000U, 0x010090U, 0x201800U, 0x080022U, 0x011400U, 0x080020U, 0x080021U, + 0x408800U, 0x040210U, 0x080024U, 0x102100U, 0x000400U, 0x000401U, 0x000402U, 0x000403U, 0x000404U, 0x000405U, + 0x000406U, 0x108200U, 0x000408U, 0x000409U, 0x00040AU, 0x002140U, 0x00040CU, 0x4C0000U, 0x210800U, 0x001090U, + 0x000410U, 0x000411U, 0x000412U, 0x244000U, 0x000414U, 0x000860U, 0x0A0100U, 0x001088U, 0x000418U, 0x038000U, + 0x400220U, 0x001084U, 0x106000U, 0x001082U, 0x001081U, 0x001080U, 0x000420U, 0x000421U, 0x000422U, 0x091000U, + 0x000424U, 0x000850U, 0x042080U, 0x600100U, 0x000428U, 0x300080U, 0x400210U, 0x048800U, 0x009100U, 0x012200U, + 0x180040U, 0x024400U, 0x000430U, 0x000844U, 0x400208U, 0x122000U, 0x000841U, 0x000840U, 0x01C000U, 0x000842U, + 0x400202U, 0x084100U, 0x400200U, 0x400201U, 0x260000U, 0x000848U, 0x400204U, 0x0010A0U, 0x000440U, 0x000441U, + 0x000442U, 0x002108U, 0x000444U, 0x000830U, 0x405000U, 0x070000U, 0x000448U, 0x002102U, 0x002101U, 0x002100U, + 0x020280U, 0x20C000U, 0x180020U, 0x002104U, 0x000450U, 0x000824U, 0x110080U, 0x488000U, 0x000821U, 0x000820U, + 0x202200U, 0x000822U, 0x281000U, 0x140200U, 0x024800U, 0x002110U, 0x410100U, 0x000828U, 0x048400U, 0x0010C0U, + 0x000460U, 0x000814U, 0x228000U, 0x004280U, 0x000811U, 0x000810U, 0x180008U, 0x000812U, 0x054000U, 0x421000U, + 0x180004U, 0x002120U, 0x180002U, 0x000818U, 0x180000U, 0x180001U, 0x000805U, 0x000804U, 0x041100U, 0x000806U, + 0x000801U, 0x000800U, 0x000803U, 0x000802U, 0x00A080U, 0x00080CU, 0x400240U, 0x210400U, 0x000809U, 0x000808U, + 0x180010U, 0x00080AU, 0x000480U, 0x000481U, 0x000482U, 0x420800U, 0x000484U, 0x014100U, 0x042020U, 0x001018U, + 0x000488U, 0x300020U, 0x08C000U, 0x001014U, 0x020240U, 0x001012U, 0x001011U, 0x001010U, 0x000490U, 0x082200U, + 0x110040U, 0x00100CU, 0x608000U, 0x00100AU, 0x001009U, 0x001008U, 0x040900U, 0x001006U, 0x001005U, 0x001004U, + 0x001003U, 0x001002U, 0x001001U, 0x001000U, 0x0004A0U, 0x300008U, 0x042004U, 0x004240U, 0x042002U, 0x0A8000U, + 0x042000U, 0x042001U, 0x300001U, 0x300000U, 0x030100U, 0x300002U, 0x404800U, 0x300004U, 0x042008U, 0x001030U, + 0x025000U, 0x450000U, 0x280800U, 0x008500U, 0x100300U, 0x0008C0U, 0x042010U, 0x001028U, 0x00A040U, 0x300010U, + 0x400280U, 0x001024U, 0x090400U, 0x001022U, 0x001021U, 0x001020U, 0x0004C0U, 0x049000U, 0x110010U, 0x004220U, + 0x020208U, 0x502000U, 0x008900U, 0x280400U, 0x020204U, 0x090800U, 0x640000U, 0x002180U, 0x020200U, 0x020201U, + 0x020202U, 0x001050U, 0x110002U, 0x220100U, 0x110000U, 0x110001U, 0x0C4000U, 0x0008A0U, 0x110004U, 0x001048U, + 0x00A020U, 0x404400U, 0x110008U, 0x001044U, 0x020210U, 0x001042U, 0x001041U, 0x001040U, 0x480100U, 0x004202U, + 0x004201U, 0x004200U, 0x211000U, 0x000890U, 0x042040U, 0x004204U, 0x00A010U, 0x300040U, 0x001C00U, 0x004208U, + 0x020220U, 0x040500U, 0x180080U, 0x418000U, 0x00A008U, 0x000884U, 0x110020U, 0x004210U, 0x000881U, 0x000880U, + 0x420400U, 0x000882U, 0x00A000U, 0x00A001U, 0x00A002U, 0x0E0000U, 0x00A004U, 0x000888U, 0x204100U, 0x001060U, + 0x000500U, 0x000501U, 0x000502U, 0x002048U, 0x000504U, 0x014080U, 0x0A0010U, 0x600020U, 0x000508U, 0x002042U, + 0x002041U, 0x002040U, 0x009020U, 0x120800U, 0x044200U, 0x002044U, 0x000510U, 0x501000U, 0x0A0004U, 0x010A00U, + 0x0A0002U, 0x04A000U, 0x0A0000U, 0x0A0001U, 0x040880U, 0x084020U, 0x308000U, 0x002050U, 0x410040U, 0x200600U, + 0x0A0008U, 0x001180U, 0x000520U, 0x060200U, 0x104800U, 0x600004U, 0x009008U, 0x600002U, 0x600001U, 0x600000U, + 0x009004U, 0x084010U, 0x030080U, 0x002060U, 0x009000U, 0x009001U, 0x009002U, 0x600008U, 0x212000U, 0x084008U, + 0x041040U, 0x008480U, 0x100280U, 0x000940U, 0x0A0020U, 0x600010U, 0x084001U, 0x084000U, 0x400300U, 0x084002U, + 0x009010U, 0x084004U, 0x002C00U, 0x150000U, 0x000540U, 0x00200AU, 0x002009U, 0x002008U, 0x340000U, 0x081200U, + 0x008880U, 0x00200CU, 0x002003U, 0x002002U, 0x002001U, 0x002000U, 0x410010U, 0x002006U, 0x002005U, 0x002004U, + 0x00C200U, 0x220080U, 0x041020U, 0x002018U, 0x410008U, 0x000920U, 0x0A0040U, 0x104400U, 0x410004U, 0x002012U, + 0x002011U, 0x002010U, 0x410000U, 0x410001U, 0x410002U, 0x002014U, 0x480080U, 0x118000U, 0x041010U, 0x002028U, + 0x026000U, 0x000910U, 0x010600U, 0x600040U, 0x200A00U, 0x002022U, 0x002021U, 0x002020U, 0x009040U, 0x040480U, + 0x180100U, 0x002024U, 0x041002U, 0x000904U, 0x041000U, 0x041001U, 0x000901U, 0x000900U, 0x041004U, 0x000902U, + 0x120400U, 0x084040U, 0x041008U, 0x002030U, 0x410020U, 0x000908U, 0x204080U, 0x028200U, 0x000580U, 0x014004U, + 0x201200U, 0x1C0000U, 0x014001U, 0x014000U, 0x008840U, 0x014002U, 0x040810U, 0x408200U, 0x030020U, 0x0020C0U, + 0x282000U, 0x014008U, 0x500400U, 0x001110U, 0x040808U, 0x220040U, 0x406000U, 0x008420U, 0x100220U, 0x014010U, + 0x0A0080U, 0x001108U, 0x040800U, 0x040801U, 0x040802U, 0x001104U, 0x040804U, 0x001102U, 0x001101U, 0x001100U, + 0x480040U, 0x003800U, 0x030008U, 0x008410U, 0x100210U, 0x014020U, 0x042100U, 0x600080U, 0x030002U, 0x300100U, + 0x030000U, 0x030001U, 0x009080U, 0x040440U, 0x030004U, 0x080A00U, 0x100204U, 0x008402U, 0x008401U, 0x008400U, + 0x100200U, 0x100201U, 0x100202U, 0x008404U, 0x040820U, 0x084080U, 0x030010U, 0x008408U, 0x100208U, 0x422000U, + 0x204040U, 0x001120U, 0x480020U, 0x220010U, 0x008804U, 0x002088U, 0x008802U, 0x014040U, 0x008800U, 0x008801U, + 0x105000U, 0x002082U, 0x002081U, 0x002080U, 0x020300U, 0x040420U, 0x008808U, 0x002084U, 0x220001U, 0x220000U, + 0x110100U, 0x220002U, 0x003400U, 0x220004U, 0x008810U, 0x440200U, 0x040840U, 0x220008U, 0x080600U, 0x002090U, + 0x410080U, 0x188000U, 0x204020U, 0x001140U, 0x480000U, 0x480001U, 0x480002U, 0x004300U, 0x480004U, 0x040408U, + 0x008820U, 0x121000U, 0x480008U, 0x040404U, 0x030040U, 0x0020A0U, 0x040401U, 0x040400U, 0x204010U, 0x040402U, + 0x480010U, 0x220020U, 0x041080U, 0x008440U, 0x100240U, 0x000980U, 0x204008U, 0x092000U, 0x00A100U, 0x011200U, + 0x204004U, 0x500800U, 0x204002U, 0x040410U, 0x204000U, 0x204001U, 0x000600U, 0x000601U, 0x000602U, 0x108004U, + 0x000604U, 0x108002U, 0x108001U, 0x108000U, 0x000608U, 0x005800U, 0x400030U, 0x2A0000U, 0x0200C0U, 0x012020U, + 0x044100U, 0x108008U, 0x000610U, 0x082080U, 0x400028U, 0x010900U, 0x051000U, 0x424000U, 0x202040U, 0x108010U, + 0x400022U, 0x140040U, 0x400020U, 0x400021U, 0x088800U, 0x200500U, 0x400024U, 0x001280U, 0x000620U, 0x060100U, + 0x400018U, 0x0040C0U, 0x284000U, 0x012008U, 0x021800U, 0x108020U, 0x400012U, 0x012004U, 0x400010U, 0x400011U, + 0x012001U, 0x012000U, 0x400014U, 0x012002U, 0x40000AU, 0x209000U, 0x400008U, 0x400009U, 0x100180U, 0x000A40U, + 0x40000CU, 0x0C0400U, 0x400002U, 0x400003U, 0x400000U, 0x400001U, 0x400006U, 0x012010U, 0x400004U, 0x400005U, + 0x000640U, 0x610000U, 0x0C0800U, 0x0040A0U, 0x020088U, 0x081100U, 0x202010U, 0x108040U, 0x020084U, 0x140010U, + 0x019000U, 0x002300U, 0x020080U, 0x020081U, 0x020082U, 0x400C00U, 0x00C100U, 0x140008U, 0x202004U, 0x021400U, + 0x202002U, 0x000A20U, 0x202000U, 0x202001U, 0x140001U, 0x140000U, 0x400060U, 0x140002U, 0x020090U, 0x140004U, + 0x202008U, 0x094000U, 0x103000U, 0x004082U, 0x004081U, 0x004080U, 0x448000U, 0x000A10U, 0x010500U, 0x004084U, + 0x200900U, 0x088400U, 0x400050U, 0x004088U, 0x0200A0U, 0x012040U, 0x180200U, 0x241000U, 0x0B0000U, 0x000A04U, + 0x400048U, 0x004090U, 0x000A01U, 0x000A00U, 0x202020U, 0x000A02U, 0x400042U, 0x140020U, 0x400040U, 0x400041U, + 0x005400U, 0x000A08U, 0x400044U, 0x028100U, 0x000680U, 0x082010U, 0x201100U, 0x004060U, 0x020048U, 0x240800U, + 0x490000U, 0x108080U, 0x020044U, 0x408100U, 0x102800U, 0x050400U, 0x020040U, 0x020041U, 0x020042U, 0x001210U, + 0x082001U, 0x082000U, 0x068000U, 0x082002U, 0x100120U, 0x082004U, 0x004C00U, 0x001208U, 0x214000U, 0x082008U, + 0x4000A0U, 0x001204U, 0x020050U, 0x001202U, 0x001201U, 0x001200U, 0x018800U, 0x004042U, 0x004041U, 0x004040U, + 0x100110U, 0x401400U, 0x042200U, 0x004044U, 0x0C1000U, 0x300200U, 0x400090U, 0x004048U, 0x020060U, 0x012080U, + 0x208400U, 0x080900U, 0x100104U, 0x082020U, 0x400088U, 0x004050U, 0x100100U, 0x100101U, 0x100102U, 0x230000U, + 0x400082U, 0x020C00U, 0x400080U, 0x400081U, 0x100108U, 0x04C000U, 0x400084U, 0x001220U, 0x02000CU, 0x004022U, + 0x004021U, 0x004020U, 0x020008U, 0x020009U, 0x02000AU, 0x004024U, 0x020004U, 0x020005U, 0x020006U, 0x004028U, + 0x020000U, 0x020001U, 0x020002U, 0x020003U, 0x401800U, 0x082040U, 0x110200U, 0x004030U, 0x020018U, 0x018400U, + 0x202080U, 0x440100U, 0x020014U, 0x140080U, 0x080500U, 0x208800U, 0x020010U, 0x020011U, 0x020012U, 0x001240U, + 0x004003U, 0x004002U, 0x004001U, 0x004000U, 0x020028U, 0x004006U, 0x004005U, 0x004004U, 0x020024U, 0x00400AU, + 0x004009U, 0x004008U, 0x020020U, 0x020021U, 0x020022U, 0x00400CU, 0x240400U, 0x004012U, 0x004011U, 0x004010U, + 0x100140U, 0x000A80U, 0x089000U, 0x004014U, 0x00A200U, 0x011100U, 0x4000C0U, 0x004018U, 0x020030U, 0x680000U, + 0x050800U, 0x102400U, 0x000700U, 0x060020U, 0x201080U, 0x010810U, 0x402800U, 0x081040U, 0x044008U, 0x108100U, + 0x190000U, 0x408080U, 0x044004U, 0x002240U, 0x044002U, 0x200410U, 0x044000U, 0x044001U, 0x00C040U, 0x010802U, + 0x010801U, 0x010800U, 0x1000A0U, 0x200408U, 0x0A0200U, 0x010804U, 0x023000U, 0x200404U, 0x400120U, 0x010808U, + 0x200401U, 0x200400U, 0x044010U, 0x200402U, 0x060001U, 0x060000U, 0x08A000U, 0x060002U, 0x100090U, 0x060004U, + 0x010440U, 0x600200U, 0x200840U, 0x060008U, 0x400110U, 0x101400U, 0x009200U, 0x012100U, 0x044020U, 0x080880U, + 0x100084U, 0x060010U, 0x400108U, 0x010820U, 0x100080U, 0x100081U, 0x100082U, 0x007000U, 0x400102U, 0x084200U, + 0x400100U, 0x400101U, 0x100088U, 0x200420U, 0x400104U, 0x028040U, 0x00C010U, 0x081004U, 0x520000U, 0x002208U, + 0x081001U, 0x081000U, 0x010420U, 0x081002U, 0x200820U, 0x002202U, 0x002201U, 0x002200U, 0x020180U, 0x081008U, + 0x044040U, 0x002204U, 0x00C000U, 0x00C001U, 0x00C002U, 0x010840U, 0x00C004U, 0x081010U, 0x202100U, 0x440080U, + 0x00C008U, 0x140100U, 0x080480U, 0x002210U, 0x410200U, 0x200440U, 0x101800U, 0x028020U, 0x200808U, 0x060040U, + 0x010404U, 0x004180U, 0x010402U, 0x081020U, 0x010400U, 0x010401U, 0x200800U, 0x200801U, 0x200802U, 0x002220U, + 0x200804U, 0x504000U, 0x010408U, 0x028010U, 0x00C020U, 0x402400U, 0x041200U, 0x380000U, 0x1000C0U, 0x000B00U, + 0x010410U, 0x028008U, 0x200810U, 0x011080U, 0x400140U, 0x028004U, 0x0C2000U, 0x028002U, 0x028001U, 0x028000U, + 0x201002U, 0x408008U, 0x201000U, 0x201001U, 0x100030U, 0x014200U, 0x201004U, 0x022400U, 0x408001U, 0x408000U, + 0x201008U, 0x408002U, 0x020140U, 0x408004U, 0x044080U, 0x080820U, 0x100024U, 0x082100U, 0x201010U, 0x010880U, + 0x100020U, 0x100021U, 0x100022U, 0x440040U, 0x040A00U, 0x408010U, 0x080440U, 0x124000U, 0x100028U, 0x200480U, + 0x01A000U, 0x001300U, 0x100014U, 0x060080U, 0x201020U, 0x004140U, 0x100010U, 0x100011U, 0x100012U, 0x080808U, + 0x006400U, 0x408020U, 0x030200U, 0x080804U, 0x100018U, 0x080802U, 0x080801U, 0x080800U, 0x100004U, 0x100005U, + 0x100006U, 0x008600U, 0x100000U, 0x100001U, 0x100002U, 0x100003U, 0x10000CU, 0x011040U, 0x400180U, 0x242000U, + 0x100008U, 0x100009U, 0x10000AU, 0x080810U, 0x052000U, 0x100C00U, 0x201040U, 0x004120U, 0x020108U, 0x081080U, + 0x008A00U, 0x440010U, 0x020104U, 0x408040U, 0x080410U, 0x002280U, 0x020100U, 0x020101U, 0x020102U, 0x310000U, + 0x00C080U, 0x220200U, 0x080408U, 0x440004U, 0x100060U, 0x440002U, 0x440001U, 0x440000U, 0x080402U, 0x011020U, + 0x080400U, 0x080401U, 0x020110U, 0x006800U, 0x080404U, 0x440008U, 0x480200U, 0x004102U, 0x004101U, 0x004100U, + 0x100050U, 0x20A000U, 0x010480U, 0x004104U, 0x200880U, 0x011010U, 0x148000U, 0x004108U, 0x020120U, 0x040600U, + 0x403000U, 0x080840U, 0x100044U, 0x011008U, 0x022800U, 0x004110U, 0x100040U, 0x100041U, 0x100042U, 0x440020U, + 0x011001U, 0x011000U, 0x080420U, 0x011002U, 0x100048U, 0x011004U, 0x204200U, 0x028080U }; + +#define X22 0x00400000 /* vector representation of X^{22} */ +#define X11 0x00000800 /* vector representation of X^{11} */ +#define MASK12 0xfffff800 /* auxiliary vector for testing */ +#define GENPOL 0x00000c75 /* generator polynomial, g(x) */ + +// --------------------------------------------------------------------------- +// Static Class Members +// --------------------------------------------------------------------------- + +/* Decode Golay (23,12,7) FEC. */ + +uint32_t Golay24128::decode23127(uint32_t code) +{ + uint32_t syndrome = getSyndrome23127(code); + uint32_t error_pattern = DECODING_TABLE_23127[syndrome]; + + code ^= error_pattern; + + return code >> 11; +} + +/* Decode Golay (24,12,8) FEC. */ + +bool Golay24128::decode24128(uint32_t code, uint32_t& out) +{ + uint32_t syndrome = getSyndrome23127(code >> 1); + uint32_t error_pattern = DECODING_TABLE_23127[syndrome] << 1; + + out = code ^ error_pattern; + + bool valid = (Utils::countBits32(syndrome) < 3U) || !(Utils::countBits32(out) & 1); + out >>= 12; + + return valid; +} + +/* Decode Golay (24,12,8) FEC. */ + +bool Golay24128::decode24128(uint8_t* bytes, uint32_t& out) +{ + assert(bytes != nullptr); + + uint32_t code = (bytes[0U] << 16) | (bytes[1U] << 8) | (bytes[2U] << 0); + return decode24128(code, out); +} + +/* Decode Golay (24,12,8) FEC. */ + +void Golay24128::decode24128(uint8_t* data, const uint8_t* raw, uint32_t msglen) +{ + uint32_t i = 0; // decoded byte counter + uint32_t j = 0; // encoded byte counter + uint32_t r0, r1, r2, r3, r4, r5; // six 8-bit bytes + uint32_t v0, v1; // two 24-bit encoded symbols + uint32_t m0_hat, m1_hat; // two 12-bit decoded symbols + + // determine remainder of input length / 3 + uint32_t r = msglen % 3; + + for (i = 0; i < msglen - r; i += 3) { + // strip six input bytes (two encoded symbols) + r0 = raw[j + 0]; + r1 = raw[j + 1]; + r2 = raw[j + 2]; + r3 = raw[j + 3]; + r4 = raw[j + 4]; + r5 = raw[j + 5]; + + // pack six 8-bit symbols into two 24-bit symbols + v0 = ((r0 << 16) & 0xff0000) | ((r1 << 8) & 0x00ff00) | ((r2) & 0x0000ff); + v1 = ((r3 << 16) & 0xff0000) | ((r4 << 8) & 0x00ff00) | ((r5 << 0) & 0x0000ff); + + // decode each symbol into a 12-bit symbol + decode24128(v0, m0_hat); + decode24128(v1, m1_hat); + + // unpack two 12-bit symbols into three 8-bit bytes + data[i + 0] = ((m0_hat >> 4) & 0xff); + data[i + 1] = ((m0_hat << 4) & 0xf0) | ((m1_hat >> 8) & 0x0f); + data[i + 2] = ((m1_hat) & 0xff); + + j += 6; + } + + // if input length isn't divisible by 3, decode last 1 or two bytes + for (i = msglen - r; i < msglen; i++) { + // strip last input symbol (three bytes) + r0 = raw[j + 0]; + r1 = raw[j + 1]; + r2 = raw[j + 2]; + + // pack three 8-bit symbols into one 24-bit symbol + v0 = ((r0 << 16) & 0xff0000) | ((r1 << 8) & 0x00ff00) | ((r2) & 0x0000ff); + + // decode into a 12-bit symbol + decode24128(v0, m0_hat); + + // retain last 8 bits of 12-bit symbol + data[i] = m0_hat & 0xff; + + j += 3; + } +} + +/* Encode Golay (23,12,7) FEC. */ + +uint32_t Golay24128::encode23127(uint32_t data) +{ + return ENCODING_TABLE_23127[data]; +} + +/* Encode Golay (24,12,8) FEC. */ + +uint32_t Golay24128::encode24128(uint32_t data) +{ + return ENCODING_TABLE_24128[data]; +} + +/* Encode Golay (24,12,8) FEC. */ + +void Golay24128::encode24128(uint8_t* data, const uint8_t* raw, uint32_t msglen) +{ + uint32_t j = 0; + uint32_t s0, s1, s2; // three 8-bit symbols + uint32_t m0, m1; // two 12-bit symbols (uncoded) + uint32_t v0, v1; // two 24-bit symbols (encoded) + + // determine remainder of input length / 3 + uint32_t r = msglen % 3; + + for (uint32_t i = 0; i < msglen - r; i += 3) { + // strip three input bytes (two uncoded symbols) + s0 = raw[i + 0]; + s1 = raw[i + 1]; + s2 = raw[i + 2]; + + // pack into two 12-bit symbols + m0 = ((s0 << 4) & 0x0ff0) | ((s1 >> 4) & 0x000f); + m1 = ((s1 << 8) & 0x0f00) | ((s2) & 0x00ff); + + // encode each 12-bit symbol into a 24-bit symbol + v0 = encode24128(m0); + v1 = encode24128(m1); + + // unpack two 24-bit symbols into six 8-bit bytes + // retaining order of bits in output + data[j + 0] = (v0 >> 16) & 0xff; + data[j + 1] = (v0 >> 8) & 0xff; + data[j + 2] = (v0) & 0xff; + data[j + 3] = (v1 >> 16) & 0xff; + data[j + 4] = (v1 >> 8) & 0xff; + data[j + 5] = (v1) & 0xff; + + j += 6; + } + + // if input length isn't divisible by 3, encode last 1 or two bytes + for (uint32_t i = msglen - r; i < msglen; i++) { + // strip last input symbol + s0 = raw[i]; + + // extend as 12-bit symbol + m0 = s0; + + // encode into 24-bit symbol + v0 = encode24128(m0); + + // unpack one 24-bit symbol into three 8-bit bytes, and + // append to output array + data[j + 0] = (v0 >> 16) & 0xff; + data[j + 1] = (v0 >> 8) & 0xff; + data[j + 2] = (v0) & 0xff; + + j += 3; + } +} + +// --------------------------------------------------------------------------- +// Private Static Class Members +// --------------------------------------------------------------------------- + +/* Compute the syndrome corresponding to the given pattern, i.e., the remainder after dividing the + pattern (when considering it as the vector representation of a polynomial) by the generator + polynomial, GENPOL. In the program this pattern has several meanings: (1) pattern = information bits, + when constructing the encoding table; (2) pattern = error pattern, when constructing the decoding + table; and (3) pattern = received vector, to obtain its syndrome in decoding. */ + +uint32_t Golay24128::getSyndrome23127(uint32_t pattern) +{ + uint32_t aux = X22; + + if (pattern >= X11) { + while (pattern & MASK12) { + while (!(aux & pattern)) + aux = aux >> 1; + + pattern ^= (aux / X11) * GENPOL; + } + } + + return pattern; +} diff --git a/vocoder/Golay24128.h b/vocoder/Golay24128.h new file mode 100644 index 0000000..94d9a17 --- /dev/null +++ b/vocoder/Golay24128.h @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - Common Library + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright (C) 2010,2016,2021 Jonathan Naylor, G4KLX + * Copyright (C) 2017,2022 Bryan Biedenkapp, N2PLL + * + */ +/** + * @file Golay24128.h + * @ingroup edac + * @file Golay24128.cpp + * @ingroup edac + */ +#if !defined(__GOLAY24128_H__) +#define __GOLAY24128_H__ + +#include "Defines.h" + +namespace edac +{ + // --------------------------------------------------------------------------- + // Class Declaration + // --------------------------------------------------------------------------- + + /** + * @brief Implements Golay (23,12,7) and Golay (24,12,8) forward error + * correction. + * @ingroup edac + */ + class HOST_SW_API Golay24128 { + public: + /** + * @brief Decode Golay (23,12,7) FEC. + * @param code + * @returns uint32_t Data decoded with Golay FEC + */ + static uint32_t decode23127(uint32_t code); + /** + * @brief Decode Golay (24,12,8) FEC. + * @param code + * @param out + * @returns bool + */ + static bool decode24128(uint32_t code, uint32_t& out); + /** + * @brief Decode Golay (24,12,8) FEC. + * @param bytes Golay FEC encoded data byte array. + * @param out + * @returns bool + */ + static bool decode24128(uint8_t* bytes, uint32_t& out); + /** + * @brief Decode Golay (24,12,8) FEC. + * @param data Data decoded with Golay FEC. + * @param raw Raw data to decode. + * @param msglen Length of data to decode. + */ + static void decode24128(uint8_t* data, const uint8_t* raw, uint32_t msglen); + + /** + * @brief Encode Golay (23,12,7) FEC. + * @param data Data to encode with Golay FEC. + * @returns uint32_t + */ + static uint32_t encode23127(uint32_t data); + /** + * @brief Encode Golay (24,12,8) FEC. + * @param data Data to encode with Golay FEC. + * @returns uint32_t + */ + static uint32_t encode24128(uint32_t data); + /** + * @brief Encode Golay (24,12,8) FEC. + * @param data Data encoded with Golay FEC. + * @param raw Raw data to encode. + * @param msglen Length of data to encode. + */ + static void encode24128(uint8_t* data, const uint8_t* raw, uint32_t msglen); + + private: + /** + * @brief Compute the syndrome corresponding to the given pattern, i.e., the + * remainder after dividing the pattern (when considering it as the vector + * representation of a polynomial) by the generator polynomial, GENPOL. + * In the program this pattern has several meanings: (1) pattern = information + * bits, when constructing the encoding table; (2) pattern = error pattern, + * when constructing the decoding table; and (3) pattern = received vector, to + * obtain its syndrome in decoding. + */ + static uint32_t getSyndrome23127(uint32_t pattern); + }; +} // namespace edac + +#endif // __GOLAY24128_H__ diff --git a/vocoder/Hamming.cpp b/vocoder/Hamming.cpp new file mode 100644 index 0000000..1395741 --- /dev/null +++ b/vocoder/Hamming.cpp @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - Common Library + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX + * + */ +#include "Hamming.h" + +using namespace edac; + +#include + +// --------------------------------------------------------------------------- +// Static Class Members +// --------------------------------------------------------------------------- + +/* Decode Hamming (15,11,3). */ + +bool Hamming::decode15113_1(bool* d) +{ + assert(d != nullptr); + + // Calculate the parity it should have + bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6]; + bool c1 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[7] ^ d[8] ^ d[9]; + bool c2 = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[8] ^ d[10]; + bool c3 = d[0] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[9] ^ d[10]; + + unsigned char n = 0U; + n |= (c0 != d[11]) ? 0x01U : 0x00U; + n |= (c1 != d[12]) ? 0x02U : 0x00U; + n |= (c2 != d[13]) ? 0x04U : 0x00U; + n |= (c3 != d[14]) ? 0x08U : 0x00U; + + switch (n) { + // Parity bit errors + case 0x01U: d[11] = !d[11]; return true; + case 0x02U: d[12] = !d[12]; return true; + case 0x04U: d[13] = !d[13]; return true; + case 0x08U: d[14] = !d[14]; return true; + + // Data bit errors + case 0x0FU: d[0] = !d[0]; return true; + case 0x07U: d[1] = !d[1]; return true; + case 0x0BU: d[2] = !d[2]; return true; + case 0x03U: d[3] = !d[3]; return true; + case 0x0DU: d[4] = !d[4]; return true; + case 0x05U: d[5] = !d[5]; return true; + case 0x09U: d[6] = !d[6]; return true; + case 0x0EU: d[7] = !d[7]; return true; + case 0x06U: d[8] = !d[8]; return true; + case 0x0AU: d[9] = !d[9]; return true; + case 0x0CU: d[10] = !d[10]; return true; + + // No bit errors + default: return false; + } +} + +/* Encode Hamming (15,11,3). */ + +void Hamming::encode15113_1(bool* d) +{ + assert(d != nullptr); + + // Calculate the checksum this row should have + d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6]; + d[12] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[7] ^ d[8] ^ d[9]; + d[13] = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[8] ^ d[10]; + d[14] = d[0] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[9] ^ d[10]; +} + +/* Decode Hamming (15,11,3). */ + +bool Hamming::decode15113_2(bool* d) +{ + assert(d != nullptr); + + // Calculate the checksum this row should have + bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8]; + bool c1 = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9]; + bool c2 = d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[7] ^ d[9] ^ d[10]; + bool c3 = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[10]; + + unsigned char n = 0x00U; + n |= (c0 != d[11]) ? 0x01U : 0x00U; + n |= (c1 != d[12]) ? 0x02U : 0x00U; + n |= (c2 != d[13]) ? 0x04U : 0x00U; + n |= (c3 != d[14]) ? 0x08U : 0x00U; + + switch (n) { + // Parity bit errors + case 0x01U: d[11] = !d[11]; return true; + case 0x02U: d[12] = !d[12]; return true; + case 0x04U: d[13] = !d[13]; return true; + case 0x08U: d[14] = !d[14]; return true; + + // Data bit errors + case 0x09U: d[0] = !d[0]; return true; + case 0x0BU: d[1] = !d[1]; return true; + case 0x0FU: d[2] = !d[2]; return true; + case 0x07U: d[3] = !d[3]; return true; + case 0x0EU: d[4] = !d[4]; return true; + case 0x05U: d[5] = !d[5]; return true; + case 0x0AU: d[6] = !d[6]; return true; + case 0x0DU: d[7] = !d[7]; return true; + case 0x03U: d[8] = !d[8]; return true; + case 0x06U: d[9] = !d[9]; return true; + case 0x0CU: d[10] = !d[10]; return true; + + // No bit errors + default: return false; + } +} + +/* Encode Hamming (15,11,3). */ + +void Hamming::encode15113_2(bool* d) +{ + assert(d != nullptr); + + // Calculate the checksum this row should have + d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8]; + d[12] = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9]; + d[13] = d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[7] ^ d[9] ^ d[10]; + d[14] = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[10]; +} + +/* Decode Hamming (13,9,3). */ + +bool Hamming::decode1393(bool* d) +{ + assert(d != nullptr); + + // Calculate the checksum this column should have + bool c0 = d[0] ^ d[1] ^ d[3] ^ d[5] ^ d[6]; + bool c1 = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7]; + bool c2 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8]; + bool c3 = d[0] ^ d[2] ^ d[4] ^ d[5] ^ d[8]; + + unsigned char n = 0x00U; + n |= (c0 != d[9]) ? 0x01U : 0x00U; + n |= (c1 != d[10]) ? 0x02U : 0x00U; + n |= (c2 != d[11]) ? 0x04U : 0x00U; + n |= (c3 != d[12]) ? 0x08U : 0x00U; + + switch (n) { + // Parity bit errors + case 0x01U: d[9] = !d[9]; return true; + case 0x02U: d[10] = !d[10]; return true; + case 0x04U: d[11] = !d[11]; return true; + case 0x08U: d[12] = !d[12]; return true; + + // Data bit erros + case 0x0FU: d[0] = !d[0]; return true; + case 0x07U: d[1] = !d[1]; return true; + case 0x0EU: d[2] = !d[2]; return true; + case 0x05U: d[3] = !d[3]; return true; + case 0x0AU: d[4] = !d[4]; return true; + case 0x0DU: d[5] = !d[5]; return true; + case 0x03U: d[6] = !d[6]; return true; + case 0x06U: d[7] = !d[7]; return true; + case 0x0CU: d[8] = !d[8]; return true; + + // No bit errors + default: return false; + } +} + +/* Encode Hamming (13,9,3). */ + +void Hamming::encode1393(bool* d) +{ + assert(d != nullptr); + + // Calculate the checksum this column should have + d[9] = d[0] ^ d[1] ^ d[3] ^ d[5] ^ d[6]; + d[10] = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7]; + d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8]; + d[12] = d[0] ^ d[2] ^ d[4] ^ d[5] ^ d[8]; +} + +/* Decode Hamming (10,6,3). */ + +bool Hamming::decode1063(bool* d) +{ + assert(d != nullptr); + + // Calculate the checksum this column should have + bool c0 = d[0] ^ d[1] ^ d[2] ^ d[5]; + bool c1 = d[0] ^ d[1] ^ d[3] ^ d[5]; + bool c2 = d[0] ^ d[2] ^ d[3] ^ d[4]; + bool c3 = d[1] ^ d[2] ^ d[3] ^ d[4]; + + unsigned char n = 0x00U; + n |= (c0 != d[6]) ? 0x01U : 0x00U; + n |= (c1 != d[7]) ? 0x02U : 0x00U; + n |= (c2 != d[8]) ? 0x04U : 0x00U; + n |= (c3 != d[9]) ? 0x08U : 0x00U; + + switch (n) { + // Parity bit errors + case 0x01U: d[6] = !d[6]; return true; + case 0x02U: d[7] = !d[7]; return true; + case 0x04U: d[8] = !d[8]; return true; + case 0x08U: d[9] = !d[9]; return true; + + // Data bit erros + case 0x07U: d[0] = !d[0]; return true; + case 0x0BU: d[1] = !d[1]; return true; + case 0x0DU: d[2] = !d[2]; return true; + case 0x0EU: d[3] = !d[3]; return true; + case 0x0CU: d[4] = !d[4]; return true; + case 0x03U: d[5] = !d[5]; return true; + + // No bit errors + default: return false; + } +} + +/* Encode Hamming (10,6,3). */ + +void Hamming::encode1063(bool* d) +{ + assert(d != nullptr); + + // Calculate the checksum this column should have + d[6] = d[0] ^ d[1] ^ d[2] ^ d[5]; + d[7] = d[0] ^ d[1] ^ d[3] ^ d[5]; + d[8] = d[0] ^ d[2] ^ d[3] ^ d[4]; + d[9] = d[1] ^ d[2] ^ d[3] ^ d[4]; +} + +/* Decode Hamming (16,11,4). */ + +bool Hamming::decode16114(bool* d) +{ + assert(d != nullptr); + + // Calculate the checksum this column should have + bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8]; + bool c1 = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9]; + bool c2 = d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[7] ^ d[9] ^ d[10]; + bool c3 = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[10]; + bool c4 = d[0] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[9] ^ d[10]; + + // Compare these with the actual bits + unsigned char n = 0x00U; + n |= (c0 != d[11]) ? 0x01U : 0x00U; + n |= (c1 != d[12]) ? 0x02U : 0x00U; + n |= (c2 != d[13]) ? 0x04U : 0x00U; + n |= (c3 != d[14]) ? 0x08U : 0x00U; + n |= (c4 != d[15]) ? 0x10U : 0x00U; + + switch (n) { + // Parity bit errors + case 0x01U: d[11] = !d[11]; return true; + case 0x02U: d[12] = !d[12]; return true; + case 0x04U: d[13] = !d[13]; return true; + case 0x08U: d[14] = !d[14]; return true; + case 0x10U: d[15] = !d[15]; return true; + + // Data bit errors + case 0x19U: d[0] = !d[0]; return true; + case 0x0BU: d[1] = !d[1]; return true; + case 0x1FU: d[2] = !d[2]; return true; + case 0x07U: d[3] = !d[3]; return true; + case 0x0EU: d[4] = !d[4]; return true; + case 0x15U: d[5] = !d[5]; return true; + case 0x1AU: d[6] = !d[6]; return true; + case 0x0DU: d[7] = !d[7]; return true; + case 0x13U: d[8] = !d[8]; return true; + case 0x16U: d[9] = !d[9]; return true; + case 0x1CU: d[10] = !d[10]; return true; + + // No bit errors + case 0x00U: return true; + + // Unrecoverable errors + default: return false; + } +} + +/* Encode Hamming (10,6,3). */ + +void Hamming::encode16114(bool* d) +{ + assert(d != nullptr); + + d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8]; + d[12] = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9]; + d[13] = d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[7] ^ d[9] ^ d[10]; + d[14] = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[10]; + d[15] = d[0] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[9] ^ d[10]; +} + +/* Decode Hamming (17,12,3). */ + +bool Hamming::decode17123(bool* d) +{ + assert(d != nullptr); + + // Calculate the checksum this column should have + bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[6] ^ d[7] ^ d[9]; + bool c1 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[7] ^ d[8] ^ d[10]; + bool c2 = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[8] ^ d[9] ^ d[11]; + bool c3 = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[10]; + bool c4 = d[0] ^ d[1] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[11]; + + // Compare these with the actual bits + unsigned char n = 0x00U; + n |= (c0 != d[12]) ? 0x01U : 0x00U; + n |= (c1 != d[13]) ? 0x02U : 0x00U; + n |= (c2 != d[14]) ? 0x04U : 0x00U; + n |= (c3 != d[15]) ? 0x08U : 0x00U; + n |= (c4 != d[16]) ? 0x10U : 0x00U; + + switch (n) { + // Parity bit errors + case 0x01U: d[12] = !d[12]; return true; + case 0x02U: d[13] = !d[13]; return true; + case 0x04U: d[14] = !d[14]; return true; + case 0x08U: d[15] = !d[15]; return true; + case 0x10U: d[16] = !d[16]; return true; + + // Data bit errors + case 0x1BU: d[0] = !d[0]; return true; + case 0x1FU: d[1] = !d[1]; return true; + case 0x17U: d[2] = !d[2]; return true; + case 0x07U: d[3] = !d[3]; return true; + case 0x0EU: d[4] = !d[4]; return true; + case 0x1CU: d[5] = !d[5]; return true; + case 0x11U: d[6] = !d[6]; return true; + case 0x0BU: d[7] = !d[7]; return true; + case 0x16U: d[8] = !d[8]; return true; + case 0x05U: d[9] = !d[9]; return true; + case 0x0AU: d[10] = !d[10]; return true; + case 0x14U: d[11] = !d[11]; return true; + + // No bit errors + case 0x00U: return true; + + // Unrecoverable errors + default: return false; + } +} + +/* Encode Hamming (17,12,3). */ + +void Hamming::encode17123(bool* d) +{ + assert(d != nullptr); + + d[12] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[6] ^ d[7] ^ d[9]; + d[13] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[7] ^ d[8] ^ d[10]; + d[14] = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[8] ^ d[9] ^ d[11]; + d[15] = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[10]; + d[16] = d[0] ^ d[1] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[11]; +} diff --git a/vocoder/Hamming.h b/vocoder/Hamming.h new file mode 100644 index 0000000..36745af --- /dev/null +++ b/vocoder/Hamming.h @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - Common Library + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX + * + */ +/** + * @file Hamming.h + * @ingroup edac + * @file Hamming.cpp + * @ingroup edac + */ +#if !defined(__HAMMING_H__) +#define __HAMMING_H__ + +#include "Defines.h" + +namespace edac +{ + // --------------------------------------------------------------------------- + // Class Declaration + // --------------------------------------------------------------------------- + + /** + * @brief Implements Hamming (15,11,3), (13,9,3), (10,6,3), (16,11,4) and + * (17, 12, 3) forward error correction. + * @ingroup edac + */ + class HOST_SW_API Hamming { + public: + /** + * @brief Decode Hamming (15,11,3). + * @param d Boolean bit array. + * @returns bool True, if bit errors are detected, otherwise false. + */ + static bool decode15113_1(bool* d); + /** + * @brief Encode Hamming (15,11,3). + * @param d Boolean bit array. + */ + static void encode15113_1(bool* d); + + /** + * @brief Decode Hamming (15,11,3). + * @param d Boolean bit array. + * @returns bool True, if bit errors are detected, otherwise false. + */ + static bool decode15113_2(bool* d); + /** + * @brief Encode Hamming (15,11,3). + * @param d Boolean bit array. + */ + static void encode15113_2(bool* d); + + /** + * @brief Decode Hamming (13,9,3). + * @param d Boolean bit array. + * @returns bool True, if bit errors are detected, otherwise false. + */ + static bool decode1393(bool* d); + /** + * @brief Encode Hamming (13,9,3). + * @param d Boolean bit array. + */ + static void encode1393(bool* d); + + /** + * @brief Decode Hamming (10,6,3). + * @param d Boolean bit array. + * @returns bool True, if bit errors are detected, otherwise false. + */ + static bool decode1063(bool* d); + /** + * @brief Encode Hamming (10,6,3). + * @param d Boolean bit array. + */ + static void encode1063(bool* d); + + /** + * @brief Decode Hamming (16,11,4). + * @param d Boolean bit array. + * @returns bool True, if bit errors are detected, otherwise false. + */ + static bool decode16114(bool* d); + /** + * @brief Encode Hamming (16,11,4). + * @param d Boolean bit array. + */ + static void encode16114(bool* d); + + /** + * @brief Decode Hamming (17,12,3). + * @param d Boolean bit array. + * @returns bool True, if bit errors are detected, otherwise false. + */ + static bool decode17123(bool* d); + /** + * @brief Encode Hamming (17,12,3). + * @param d Boolean bit array. + */ + static void encode17123(bool* d); + }; +} // namespace edac + +#endif // __HAMMING_H__ diff --git a/vocoder/MBEDecoder.cpp b/vocoder/MBEDecoder.cpp new file mode 100644 index 0000000..4383bc2 --- /dev/null +++ b/vocoder/MBEDecoder.cpp @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - MBE Vocoder + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright (C) 2019-2021 Doug McLain + * Copyright (C) 2021 Bryan Biedenkapp, N2PLL + * + */ +#include +#include +#include + +#include "Golay24128.h" +#include "MBEDecoder.h" + +using namespace edac; +using namespace vocoder; + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +const int MBEDecoder::dW[72] = { 0,0,3,2,1,1,0,0,1,1,0,0,3,2,1,1,3,2,1,1,0,0,3,2,0,0,3,2,1,1,0,0,1,1,0,0,3,2,1,1,3,2,1,1,0,0,3,2,0,0,3,2,1,1,0,0,1,1,0,0,3,2,1,1,3,3,2,1,0,0,3,3, }; + +const int MBEDecoder::dX[72] = { 10,22,11,9,10,22,11,23,8,20,9,21,10,8,9,21,8,6,7,19,8,20,9,7,6,18,7,5,6,18,7,19,4,16,5,17,6,4,5,17,4,2,3,15,4,16,5,3,2,14,3,1,2,14,3,15,0,12,1,13,2,0,1,13,0,12,10,11,0,12,1,13, }; + +const int MBEDecoder::rW[36] = { + 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 2, + 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2 +}; + +const int MBEDecoder::rX[36] = { + 23, 10, 22, 9, 21, 8, + 20, 7, 19, 6, 18, 5, + 17, 4, 16, 3, 15, 2, + 14, 1, 13, 0, 12, 10, + 11, 9, 10, 8, 9, 7, + 8, 6, 7, 5, 6, 4 +}; + +// bit 0 +const int MBEDecoder::rY[36] = { + 0, 2, 0, 2, 0, 2, + 0, 2, 0, 3, 0, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3 +}; + +const int MBEDecoder::rZ[36] = { + 5, 3, 4, 2, 3, 1, + 2, 0, 1, 13, 0, 12, + 22, 11, 21, 10, 20, 9, + 19, 8, 18, 7, 17, 6, + 16, 5, 15, 4, 14, 3, + 13, 2, 12, 1, 11, 0 +}; + +// --------------------------------------------------------------------------- +// Public Class Members +// --------------------------------------------------------------------------- + +/* Initializes a new instance of the MBEDecoder class. */ + +MBEDecoder::MBEDecoder(MBE_DECODER_MODE mode) : + m_mbelibParms(NULL), + m_mbeMode(mode), + m_gainAdjust(1.0f) +{ + m_mbelibParms = new mbelibParms(); + mbe_initMbeParms(m_mbelibParms->m_cur_mp, m_mbelibParms->m_prev_mp, m_mbelibParms->m_prev_mp_enhanced); + + ::memset(gainMaxBuf, 0, sizeof(float) * 200); + gainMaxBufPtr = gainMaxBuf; + gainMaxIdx = 0; +} + +/* Finalizes a instance of the MBEDecoder class. */ + +MBEDecoder::~MBEDecoder() +{ + delete m_mbelibParms; +} + +/* Decodes the given MBE codewords to deinterleaved MBE bits using the decoder mode. */ + +int32_t MBEDecoder::decodeBits(uint8_t* codeword, char* mbeBits) +{ + int32_t errs = 0; + float samples[160U]; + ::memset(samples, 0x00U, 160U * sizeof(float)); + + switch (m_mbeMode) + { + case DECODE_DMR_AMBE: + { + char ambe_d[49U]; + char ambe_fr[4][24]; + ::memset(ambe_d, 0x00U, 49U); + ::memset(ambe_fr, 0x00U, 96U); + + const int* w, *x, *y, *z; + + w = rW; + x = rX; + y = rY; + z = rZ; + + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 8; j += 2) { + ambe_fr[*y][*z] = (1 & (codeword[i] >> (7 - (j + 1)))); + ambe_fr[*w][*x] = (1 & (codeword[i] >> (7 - j))); + w++; + x++; + y++; + z++; + } + } + + errs = mbe_eccAmbe3600x2450C0(ambe_fr); + mbe_demodulateAmbe3600x2450Data(ambe_fr); + + errs += mbe_eccAmbe3600x2450Data(ambe_fr, ambe_d); + + ::memcpy(mbeBits, ambe_d, 49U); + } + break; + + case DECODE_88BIT_IMBE: + { + char imbe_d[88U]; + ::memset(imbe_d, 0x00U, 88U); + + for (int i = 0; i < 11; ++i) { + for (int j = 0; j < 8; j++) { + imbe_d[j + (8 * i)] = (1 & (codeword[i] >> (7 - j))); + } + } + + ::memcpy(mbeBits, imbe_d, 88U); + } + break; + } + + return errs; +} + +/* Decodes the given MBE codewords to PCM samples using the decoder mode. */ + +int32_t MBEDecoder::decodeF(uint8_t* codeword, float samples[]) +{ + int32_t errs = 0; + switch (m_mbeMode) + { + case DECODE_DMR_AMBE: + { + char ambe_d[49U]; + char ambe_fr[4][24]; + ::memset(ambe_d, 0x00U, 49U); + ::memset(ambe_fr, 0x00U, 96U); + + const int* w, *x, *y, *z; + + w = rW; + x = rX; + y = rY; + z = rZ; + + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 8; j += 2) { + ambe_fr[*y][*z] = (1 & (codeword[i] >> (7 - (j + 1)))); + ambe_fr[*w][*x] = (1 & (codeword[i] >> (7 - j))); + w++; + x++; + y++; + z++; + } + } + + int ambeErrs; + char ambeErrStr[64U]; + ::memset(ambeErrStr, 0x20U, 64U); + + mbe_processAmbe3600x2450FrameF(samples, &ambeErrs, &errs, ambeErrStr, ambe_fr, ambe_d, m_mbelibParms->m_cur_mp, m_mbelibParms->m_prev_mp, m_mbelibParms->m_prev_mp_enhanced, 3); + } + break; + + case DECODE_88BIT_IMBE: + { + char imbe_d[88U]; + ::memset(imbe_d, 0x00U, 88U); + + for (int i = 0; i < 11; ++i) { + for (int j = 0; j < 8; j++) { + imbe_d[j + (8 * i)] = (1 & (codeword[i] >> (7 - j))); + } + } + + int ambeErrs; + char ambeErrStr[64U]; + ::memset(ambeErrStr, 0x20U, 64U); + + mbe_processImbe4400DataF(samples, &ambeErrs, &errs, ambeErrStr, imbe_d, m_mbelibParms->m_cur_mp, m_mbelibParms->m_prev_mp, m_mbelibParms->m_prev_mp_enhanced, 3); + } + break; + } + + return errs; +} + +/* Decodes the given MBE codewords to PCM samples using the decoder mode. */ + +int32_t MBEDecoder::decode(uint8_t* codeword, int16_t samples[]) +{ + float samplesF[160U]; + ::memset(samplesF, 0x00U, 160U * sizeof(float)); + int32_t errs = decodeF(codeword, samplesF); + + float* sampleFPtr = samplesF; + if (m_autoGain) { + // detect max level + float max = 0.0f; + for (int n = 0; n < 160; n++) { + float out = fabsf(*sampleFPtr); + if (out > max) { + max = out; + } + + sampleFPtr++; + } + + *gainMaxBufPtr = max; + gainMaxBufPtr++; + gainMaxIdx++; + + if (gainMaxIdx > 24) { + gainMaxIdx = 0; + gainMaxBufPtr = gainMaxBuf; + } + + // lookup max history + for (int i = 0; i < 25; i++) { + float a = gainMaxBuf[i]; + if (a > max) { + max = a; + } + } + + // determine optimal gain level + float gainFactor = 0.0f, gainDelta = 0.0f; + if (max > static_cast(0)) { + gainFactor = (static_cast(30000) / max); + } + else { + gainFactor = static_cast(50); + } + + if (gainFactor < m_gainAdjust) { + m_gainAdjust = gainFactor; + gainDelta = static_cast(0); + } + else { + if (gainFactor > static_cast(50)) { + gainFactor = static_cast(50); + } + + gainDelta = gainFactor - m_gainAdjust; + + if (gainDelta > (static_cast(0.05) * m_gainAdjust)) { + gainDelta = (static_cast(0.05) * m_gainAdjust); + } + } + + gainDelta /= static_cast(160); + + // adjust output gain + sampleFPtr = samplesF; + for (int n = 0; n < 160; n++) { + *sampleFPtr = (m_gainAdjust + (static_cast(n) * gainDelta)) * (*sampleFPtr); + sampleFPtr++; + } + + m_gainAdjust += (static_cast(160) * gainDelta); + } + + int16_t* samplePtr = samples; + sampleFPtr = samplesF; + for (int n = 0; n < 160; n++) { + float smp = *sampleFPtr; + if (!m_autoGain) { + smp *= m_gainAdjust; + } + + // audio clipping + if (smp > 32760) { + smp = 32760; + } + else if (smp < -32760) { + smp = -32760; + } + + *samplePtr = (int16_t)(smp); + + samplePtr++; + sampleFPtr++; + } + + return errs; +} diff --git a/vocoder/MBEDecoder.h b/vocoder/MBEDecoder.h new file mode 100644 index 0000000..e419f35 --- /dev/null +++ b/vocoder/MBEDecoder.h @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - MBE Vocoder + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright (C) 2019-2021 Doug McLain + * Copyright (C) 2021 Bryan Biedenkapp, N2PLL + * + */ +/** + * @file MBEDecoder.h + * @ingroup vocoder + * @file MBEDecoder.cpp + * @ingroup vocoder + */ +#if !defined(__MBE_DECODER_H__) +#define __MBE_DECODER_H__ + +extern "C" { +#include "mbe.h" +} + +#include "Defines.h" + +#include +#include + +namespace vocoder +{ + // --------------------------------------------------------------------------- + // Structure Declaration + // --------------------------------------------------------------------------- + + struct mbelibParms + { + mbe_parms* m_cur_mp; + mbe_parms* m_prev_mp; + mbe_parms* m_prev_mp_enhanced; + + /// + mbelibParms() + { + m_cur_mp = (mbe_parms*)malloc(sizeof(mbe_parms)); + m_prev_mp = (mbe_parms*)malloc(sizeof(mbe_parms)); + m_prev_mp_enhanced = (mbe_parms*)malloc(sizeof(mbe_parms)); + } + + /// + ~mbelibParms() + { + free(m_prev_mp_enhanced); + free(m_prev_mp); + free(m_cur_mp); + } + }; + + // --------------------------------------------------------------------------- + // Constants + // --------------------------------------------------------------------------- + + /** + * @brief Vocoder Decoding Mode + */ + enum MBE_DECODER_MODE { + DECODE_DMR_AMBE, //! DMR AMBE + DECODE_88BIT_IMBE //! 88-bit IMBE (P25) + }; + + // --------------------------------------------------------------------------- + // Class Declaration + // --------------------------------------------------------------------------- + + /** + * @brief Implements MBE audio decoding. + */ + class HOST_SW_API MBEDecoder + { + public: + /** + * @brief Initializes a new instance of the MBEDecoder class. + * @param mode Decoder mode. + */ + MBEDecoder(MBE_DECODER_MODE mode); + /** + * @brief Finalizes a instance of the MBEDecoder class. + */ + ~MBEDecoder(); + + /** + * @brief Decodes the given MBE codewords to deinterleaved MBE bits using the decoder mode. + * @param[in] codeword MBE codeword. + * @param[out] mbeBits + * @returns int32_t + */ + int32_t decodeBits(uint8_t* codeword, char* mbeBits); + + /** + * @brief Decodes the given MBE codewords to PCM samples using the decoder mode. + * @param[in] codeword MBE codeword. + * @param[out] samples PCM Samples (in float format). + * @returns int32_t + */ + int32_t decodeF(uint8_t* codeword, float samples[]); + /** + * @brief Decodes the given MBE codewords to PCM samples using the decoder mode. + * @param[in] codeword MBE codeword. + * @param[out] samples PCM Samples (in short format). + * @returns int32_t + */ + int32_t decode(uint8_t* codeword, int16_t samples[]); + + private: + mbelibParms* m_mbelibParms; + + MBE_DECODER_MODE m_mbeMode; + + static const int dW[72]; + static const int dX[72]; + static const int rW[36]; + static const int rX[36]; + static const int rY[36]; + static const int rZ[36]; + + float gainMaxBuf[200]; + float* gainMaxBufPtr; + int gainMaxIdx; + + public: + /** + * @brief Gain adjustment. + */ + __PROPERTY(float, gainAdjust, GainAdjust); + /** + * @brief Flag indicating automatic gain adjustment is enabled. + */ + __PROPERTY(bool, autoGain, AutoGain); + }; +} // namespace vocoder + +#endif // __MBE_DECODER_H__ diff --git a/vocoder/MBEEncoder.cpp b/vocoder/MBEEncoder.cpp new file mode 100644 index 0000000..db68b1f --- /dev/null +++ b/vocoder/MBEEncoder.cpp @@ -0,0 +1,718 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - MBE Vocoder + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright (C) 2019-2021 Doug McLain + * Copyright (C) 2021 Bryan Biedenkapp, N2PLL + * + */ +#define _USE_MATH_DEFINES +#include + +/* + * AMBE halfrate encoder - Copyright 2016 Max H. Parke KA1RBI + * Copyright (C) 2021 by Bryan Biedenkapp N2PLL + * + * This file is part of OP25 and part of GNU Radio + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "Defines.h" +#include "AMBEFEC.h" +#include "Golay24128.h" +#include "Utils.h" +#include "MBEEncoder.h" +#include "ambe3600x2450_const.h" +#include "ambe3600x2400_const.h" + +#include + +using namespace edac; +using namespace vocoder; + +#ifdef _MSC_VER +#pragma warning(disable: 4244) +#endif + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +static const short b0_lookup[] = { + 0, 0, 0, 1, 1, 2, 2, 2, + 3, 3, 4, 4, 4, 5, 5, 5, + 6, 6, 7, 7, 7, 8, 8, 8, + 9, 9, 9, 10, 10, 11, 11, 11, + 12, 12, 12, 13, 13, 13, 14, 14, + 14, 15, 15, 15, 16, 16, 16, 17, + 17, 17, 17, 18, 18, 18, 19, 19, + 19, 20, 20, 20, 21, 21, 21, 21, + 22, 22, 22, 23, 23, 23, 24, 24, + 24, 24, 25, 25, 25, 25, 26, 26, + 26, 27, 27, 27, 27, 28, 28, 28, + 29, 29, 29, 29, 30, 30, 30, 30, + 31, 31, 31, 31, 31, 32, 32, 32, + 32, 33, 33, 33, 33, 34, 34, 34, + 34, 35, 35, 35, 35, 36, 36, 36, + 36, 37, 37, 37, 37, 38, 38, 38, + 38, 38, 39, 39, 39, 39, 40, 40, + 40, 40, 40, 41, 41, 41, 41, 42, + 42, 42, 42, 42, 43, 43, 43, 43, + 43, 44, 44, 44, 44, 45, 45, 45, + 45, 45, 46, 46, 46, 46, 46, 47, + 47, 47, 47, 47, 48, 48, 48, 48, + 48, 49, 49, 49, 49, 49, 49, 50, + 50, 50, 50, 50, 51, 51, 51, 51, + 51, 52, 52, 52, 52, 52, 52, 53, + 53, 53, 53, 53, 54, 54, 54, 54, + 54, 54, 55, 55, 55, 55, 55, 56, + 56, 56, 56, 56, 56, 57, 57, 57, + 57, 57, 57, 58, 58, 58, 58, 58, + 58, 59, 59, 59, 59, 59, 59, 60, + 60, 60, 60, 60, 60, 61, 61, 61, + 61, 61, 61, 62, 62, 62, 62, 62, + 62, 63, 63, 63, 63, 63, 63, 63, + 64, 64, 64, 64, 64, 64, 65, 65, + 65, 65, 65, 65, 65, 66, 66, 66, + 66, 66, 66, 67, 67, 67, 67, 67, + 67, 67, 68, 68, 68, 68, 68, 68, + 68, 69, 69, 69, 69, 69, 69, 69, + 70, 70, 70, 70, 70, 70, 70, 71, + 71, 71, 71, 71, 71, 71, 72, 72, + 72, 72, 72, 72, 72, 73, 73, 73, + 73, 73, 73, 73, 73, 74, 74, 74, + 74, 74, 74, 74, 75, 75, 75, 75, + 75, 75, 75, 75, 76, 76, 76, 76, + 76, 76, 76, 76, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 78, 78, 78, + 78, 78, 78, 78, 78, 79, 79, 79, + 79, 79, 79, 79, 79, 80, 80, 80, + 80, 80, 80, 80, 80, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 82, 82, + 82, 82, 82, 82, 82, 82, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 84, + 84, 84, 84, 84, 84, 84, 84, 84, + 85, 85, 85, 85, 85, 85, 85, 85, + 85, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, + 91, 91, 91, 91, 91, 91, 91, 91, + 91, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, + 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 98, + 98, 98, 98, 98, 98, 98, 98, 98, + 98, 98, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 100, 100, + 100, 100, 100, 100, 100, 100, 100, 100, + 100, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, + 103, 103, 103, 103, 103, 103, 103, 103, + 103, 103, 103, 103, 104, 104, 104, 104, + 104, 104, 104, 104, 104, 104, 104, 104, + 105, 105, 105, 105, 105, 105, 105, 105, + 105, 105, 105, 105, 106, 106, 106, 106, + 106, 106, 106, 106, 106, 106, 106, 106, + 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 108, 108, + 108, 109, 109, 109, 109, 109, 109, 109, + 109, 109, 109, 109, 109, 109, 110, 110, + 110, 110, 110, 110, 110, 110, 110, 110, + 110, 110, 110, 111, 111, 111, 111, 111, + 111, 111, 111, 111, 111, 111, 111, 111, + 112, 112, 112, 112, 112, 112, 112, 112, + 112, 112, 112, 112, 112, 112, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 114, 114, + 114, 115, 115, 115, 115, 115, 115, 115, + 115, 115, 115, 115, 115, 115, 115, 116, + 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 117, 117, + 117, 117, 117, 117, 117, 117, 117, 117, + 117, 117, 117, 117, 118, 118, 118, 118, + 118, 118, 118, 118, 118, 118, 118, 118, + 118, 118, 118, 119, 119, 119, 119, 119, + 119, 119, 119 +}; + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +/** + * @brief + * @param[in] imbe_param + * @param b + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @param gainAdjust Gain adjustment. + */ +static void encodeAMBE(const IMBE_PARAM* imbe_param, int b[], mbe_parms* cur_mp, mbe_parms* prev_mp, float gainAdjust) +{ + static const float SQRT_2 = sqrtf(2.0); + static const int b0_lmax = sizeof(b0_lookup) / sizeof(b0_lookup[0]); + // int b[9]; + + // ref_pitch is Q8_8 in range 19.875 - 123.125 + int b0_i = (imbe_param->ref_pitch >> 5) - 159; + if (b0_i < 0 || b0_i > b0_lmax) { + fprintf(stderr, "encode error b0_i %d\n", b0_i); + return; + } + + b[0] = b0_lookup[b0_i]; + int L = (int)AmbeLtable[b[0]]; + + // adjust b0 until L agrees + while (L != imbe_param->num_harms) { + if (L < imbe_param->num_harms) + b0_i++; + else if (L > imbe_param->num_harms) + b0_i--; + if (b0_i < 0 || b0_i > b0_lmax) { + fprintf(stderr, "encode error2 b0_i %d\n", b0_i); + return; + } + b[0] = b0_lookup[b0_i]; + L = (int)AmbeLtable[b[0]]; + } + + float m_float2[NUM_HARMS_MAX]; + for (int l = 1; l <= L; l++) { + m_float2[l - 1] = (float)imbe_param->sa[l - 1]; + m_float2[l - 1] = m_float2[l - 1] * m_float2[l - 1]; + } + + float en_min = 0; + b[1] = 0; + int vuv_max = 17; + for (int n = 0; n < vuv_max; n++) { + float En = 0; + for (int l = 1; l <= L; l++) { + int jl = (int)((float)l * (float)16.0 * AmbeW0table[b[0]]); + int kl = 12; + if (l <= 36) + kl = (l + 2) / 3; + + if (imbe_param->v_uv_dsn[(kl - 1) * 3] != AmbeVuv[n][jl]) + En += m_float2[l - 1]; + } + + if (n == 0) + en_min = En; + else if (En < en_min) { + b[1] = n; + en_min = En; + } + } + + // log spectral amplitudes + float num_harms_f = (float)imbe_param->num_harms; + float log_l_2 = 0.5 * log2f(num_harms_f); // fixme: table lookup + float log_l_w0 = 0.5 * log2f(num_harms_f * AmbeW0table[b[0]] * 2.0 * M_PI) + 2.289; + float lsa[NUM_HARMS_MAX]; + float lsa_sum = 0.0; + + for (int i1 = 0; i1 < imbe_param->num_harms; i1++) { + float sa = (float)imbe_param->sa[i1]; + if (sa < 1) sa = 1.0; + if (imbe_param->v_uv_dsn[i1]) + lsa[i1] = log_l_2 + log2f(sa); + else + lsa[i1] = log_l_w0 + log2f(sa); + lsa_sum += lsa[i1]; + } + + float gain = lsa_sum / num_harms_f; + float diff_gain = gain - 0.5 * prev_mp->gamma; + + diff_gain -= gainAdjust; + + float error; + int error_index; + int max_dg = 32; + for (int i1 = 0; i1 < max_dg; i1++) { + float diff = fabsf(diff_gain - AmbeDg[i1]); + if ((i1 == 0) || (diff < error)) { + error = diff; + error_index = i1; + } + } + + b[2] = error_index; + + // prediction residuals + float l_prev_l = (float)(prev_mp->L) / num_harms_f; + float tmp_s = 0.0; + prev_mp->log2Ml[0] = prev_mp->log2Ml[1]; + for (int i1 = 0; i1 < imbe_param->num_harms; i1++) { + float kl = l_prev_l * (float)(i1 + 1); + int kl_floor = (int)kl; + float kl_frac = kl - kl_floor; + tmp_s += (1.0 - kl_frac) * prev_mp->log2Ml[kl_floor + 0] + kl_frac * prev_mp->log2Ml[kl_floor + 1 + 0]; + } + + float T[NUM_HARMS_MAX]; + for (int i1 = 0; i1 < imbe_param->num_harms; i1++) { + float kl = l_prev_l * (float)(i1 + 1); + int kl_floor = (int)kl; + float kl_frac = kl - kl_floor; + T[i1] = lsa[i1] - 0.65 * (1.0 - kl_frac) * prev_mp->log2Ml[kl_floor + 0] \ + - 0.65 * kl_frac * prev_mp->log2Ml[kl_floor + 1 + 0]; + } + + // DCT + const int* J = AmbeLmprbl[imbe_param->num_harms]; + float* c[4]; + int acc = 0; + for (int i = 0; i < 4; i++) { + c[i] = &T[acc]; + acc += J[i]; + } + + float C[4][17]; + for (int i = 1; i <= 4; i++) { + for (int k = 1; k <= J[i - 1]; k++) { + float s = 0.0; + for (int j = 1; j <= J[i - 1]; j++) { + //fixme: lut? + s += (c[i - 1][j - 1] * cosf((M_PI * (((float)k) - 1.0) * (((float)j) - 0.5)) / (float)J[i - 1])); + } + C[i - 1][k - 1] = s / (float)J[i - 1]; + } + } + + float R[8]; + R[0] = C[0][0] + SQRT_2 * C[0][1]; + R[1] = C[0][0] - SQRT_2 * C[0][1]; + R[2] = C[1][0] + SQRT_2 * C[1][1]; + R[3] = C[1][0] - SQRT_2 * C[1][1]; + R[4] = C[2][0] + SQRT_2 * C[2][1]; + R[5] = C[2][0] - SQRT_2 * C[2][1]; + R[6] = C[3][0] + SQRT_2 * C[3][1]; + R[7] = C[3][0] - SQRT_2 * C[3][1]; + + // encode PRBA + float G[8]; + for (int m = 1; m <= 8; m++) { + G[m - 1] = 0.0; + for (int i = 1; i <= 8; i++) { + //fixme: lut? + G[m - 1] += (R[i - 1] * cosf((M_PI * (((float)m) - 1.0) * (((float)i) - 0.5)) / 8.0)); + } + G[m - 1] /= 8.0; + } + + for (int i = 0; i < 512; i++) { + float err = 0.0; + float diff; + + diff = G[1] - AmbePRBA24[i][0]; + err += (diff * diff); + diff = G[2] - AmbePRBA24[i][1]; + err += (diff * diff); + diff = G[3] - AmbePRBA24[i][2]; + err += (diff * diff); + + if (i == 0 || err < error) { + error = err; + error_index = i; + } + } + + b[3] = error_index; + + // PRBA58 + for (int i = 0; i < 128; i++) { + float err = 0.0; + float diff; + + diff = G[4] - AmbePRBA58[i][0]; + err += (diff * diff); + diff = G[5] - AmbePRBA58[i][1]; + err += (diff * diff); + diff = G[6] - AmbePRBA58[i][2]; + err += (diff * diff); + diff = G[7] - AmbePRBA58[i][3]; + err += (diff * diff); + + if (i == 0 || err < error) { + error = err; + error_index = i; + } + } + + b[4] = error_index; + + // higher order coeffs b5 + int ii = 1; + if (J[ii - 1] <= 2) { + b[4 + ii] = 0.0; + } + else { + int max_5 = 32; + for (int n = 0; n < max_5; n++) { + float err = 0.0; + float diff; + for (int j = 1; j <= J[ii - 1] - 2 && j <= 4; j++) { + diff = AmbeHOCb5[n][j - 1] - C[ii - 1][j + 2 - 1]; + err += (diff * diff); + } + if (n == 0 || err < error) { + error = err; + error_index = n; + } + } + b[4 + ii] = error_index; + } + + // higher order coeffs b6 + ii = 2; + if (J[ii - 1] <= 2) { + b[4 + ii] = 0.0; + } + else { + for (int n = 0; n < 16; n++) { + float err = 0.0; + float diff; + for (int j = 1; j <= J[ii - 1] - 2 && j <= 4; j++) { + diff = AmbeHOCb6[n][j - 1] - C[ii - 1][j + 2 - 1]; + err += (diff * diff); + } + if (n == 0 || err < error) { + error = err; + error_index = n; + } + } + b[4 + ii] = error_index; + } + + // higher order coeffs b7 + ii = 3; + if (J[ii - 1] <= 2) { + b[4 + ii] = 0.0; + } + else { + for (int n = 0; n < 16; n++) { + float err = 0.0; + float diff; + for (int j = 1; j <= J[ii - 1] - 2 && j <= 4; j++) { + diff = AmbeHOCb7[n][j - 1] - C[ii - 1][j + 2 - 1]; + err += (diff * diff); + } + if (n == 0 || err < error) { + error = err; + error_index = n; + } + } + b[4 + ii] = error_index; + } + + // higher order coeffs b8 + ii = 4; + if (J[ii - 1] <= 2) { + b[4 + ii] = 0.0; + } + else { + int max_8 = 8; + for (int n = 0; n < max_8; n++) { + float err = 0.0; + float diff; + for (int j = 1; j <= J[ii - 1] - 2 && j <= 4; j++) { + diff = AmbeHOCb8[n][j - 1] - C[ii - 1][j + 2 - 1]; + err += (diff * diff); + } + if (n == 0 || err < error) { + error = err; + error_index = n; + } + } + b[4 + ii] = error_index; + } + + mbe_dequantizeAmbe2250Parms(cur_mp, prev_mp, b); + mbe_moveMbeParms(cur_mp, prev_mp); +} + +/** + * @brief + * @param bits + * @param b + */ +static void encode49bit(uint8_t bits[49], const int b[9]) +{ + bits[0] = (b[0] >> 6) & 1; + bits[1] = (b[0] >> 5) & 1; + bits[2] = (b[0] >> 4) & 1; + bits[3] = (b[0] >> 3) & 1; + bits[4] = (b[1] >> 4) & 1; + bits[5] = (b[1] >> 3) & 1; + bits[6] = (b[1] >> 2) & 1; + bits[7] = (b[1] >> 1) & 1; + bits[8] = (b[2] >> 4) & 1; + bits[9] = (b[2] >> 3) & 1; + bits[10] = (b[2] >> 2) & 1; + bits[11] = (b[2] >> 1) & 1; + bits[12] = (b[3] >> 8) & 1; + bits[13] = (b[3] >> 7) & 1; + bits[14] = (b[3] >> 6) & 1; + bits[15] = (b[3] >> 5) & 1; + bits[16] = (b[3] >> 4) & 1; + bits[17] = (b[3] >> 3) & 1; + bits[18] = (b[3] >> 2) & 1; + bits[19] = (b[3] >> 1) & 1; + bits[20] = (b[4] >> 6) & 1; + bits[21] = (b[4] >> 5) & 1; + bits[22] = (b[4] >> 4) & 1; + bits[23] = (b[4] >> 3) & 1; + bits[24] = (b[5] >> 4) & 1; + bits[25] = (b[5] >> 3) & 1; + bits[26] = (b[5] >> 2) & 1; + bits[27] = (b[5] >> 1) & 1; + bits[28] = (b[6] >> 3) & 1; + bits[29] = (b[6] >> 2) & 1; + bits[30] = (b[6] >> 1) & 1; + bits[31] = (b[7] >> 3) & 1; + bits[32] = (b[7] >> 2) & 1; + bits[33] = (b[7] >> 1) & 1; + bits[34] = (b[8] >> 2) & 1; + bits[35] = b[1] & 1; + bits[36] = b[2] & 1; + bits[37] = (b[0] >> 2) & 1; + bits[38] = (b[0] >> 1) & 1; + bits[39] = b[0] & 1; + bits[40] = b[3] & 1; + bits[41] = (b[4] >> 2) & 1; + bits[42] = (b[4] >> 1) & 1; + bits[43] = b[4] & 1; + bits[44] = b[5] & 1; + bits[45] = b[6] & 1; + bits[46] = b[7] & 1; + bits[47] = (b[8] >> 1) & 1; + bits[48] = b[8] & 1; +} + +/** + * @brief + * @param[in] in + * @param out + */ +static void encodeDmrAMBE(const uint8_t* in, uint8_t* out) +{ + unsigned int aOrig = 0U; + unsigned int bOrig = 0U; + unsigned int cOrig = 0U; + + unsigned int MASK = 0x000800U; + for (unsigned int i = 0U; i < 12U; i++, MASK >>= 1) { + unsigned int n1 = i; + unsigned int n2 = i + 12U; + if (READ_BIT(in, n1)) + aOrig |= MASK; + if (READ_BIT(in, n2)) + bOrig |= MASK; + } + + MASK = 0x1000000U; + for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) { + unsigned int n = i + 24U; + if (READ_BIT(in, n)) + cOrig |= MASK; + } + + unsigned int a = Golay24128::encode24128(aOrig); + + // The PRNG + unsigned int p = PRNG_TABLE[aOrig] >> 1; + + unsigned int b = Golay24128::encode23127(bOrig) >> 1; + b ^= p; + + MASK = 0x800000U; + for (unsigned int i = 0U; i < 24U; i++, MASK >>= 1) { + unsigned int aPos = AMBE_A_TABLE[i]; + WRITE_BIT(out, aPos, a & MASK); + } + + MASK = 0x400000U; + for (unsigned int i = 0U; i < 23U; i++, MASK >>= 1) { + unsigned int bPos = AMBE_B_TABLE[i]; + WRITE_BIT(out, bPos, b & MASK); + } + + MASK = 0x1000000U; + for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) { + unsigned int cPos = AMBE_C_TABLE[i]; + WRITE_BIT(out, cPos, cOrig & MASK); + } +} + +// --------------------------------------------------------------------------- +// Public Class Members +// --------------------------------------------------------------------------- + +/* Initializes a new instance of the MBEEncoder class. */ +MBEEncoder::MBEEncoder(MBE_ENCODER_MODE mode) : + m_mbeMode(mode), + m_gainAdjust(0.0f) +{ + mbe_parms enh_mp; + mbe_initMbeParms(&m_curMBEParms, &m_prevMBEParms, &enh_mp); +} + +/* Encodes the given MBE bits to deinterleaved MBE bits using the decoder mode. */ + +void MBEEncoder::encodeBits(uint8_t* bits, uint8_t* codeword) +{ + assert(bits != nullptr); + assert(codeword != nullptr); + + int32_t errs = 0; + float samples[160U]; + ::memset(samples, 0x00U, 160U * sizeof(float)); + + switch (m_mbeMode) + { + case ENCODE_DMR_AMBE: + { + // build 49-bit AMBE bytes + uint8_t rawAmbe[9U]; + ::memset(rawAmbe, 0x00U, 9U); + + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 8; ++j) { + rawAmbe[i] |= (bits[(i * 8) + j] << (7 - j)); + } + } + + // build DMR AMBE bytes + uint8_t dmrAMBE[9U]; + ::memset(dmrAMBE, 0x00U, 9U); + + encodeDmrAMBE(rawAmbe, dmrAMBE); + ::memcpy(codeword, dmrAMBE, 9U); + } + break; + + case ENCODE_88BIT_IMBE: + { + uint8_t rawImbe[11U]; + ::memset(rawImbe, 0x00U, 11U); + + for (int i = 0; i < 11; ++i) { + for (int j = 0; j < 8; ++j) { + rawImbe[i] |= (bits[(i * 8) + j] << (7 - j)); + } + } + + ::memcpy(codeword, rawImbe, 11U); + } + break; + } +} + +/* Encodes the given PCM samples using the encoder mode to MBE codewords. */ + +void MBEEncoder::encode(int16_t* samples, uint8_t* codeword) +{ + assert(samples != nullptr); + assert(codeword != nullptr); + + int16_t frame_vector[8]; // result ignored + + // first do speech analysis to generate mbe model parameters + m_vocoder.imbe_encode(frame_vector, samples); + if (m_mbeMode == ENCODE_88BIT_IMBE) { + if (m_gainAdjust >= 1.0f) { + m_vocoder.set_gain_adjust(m_gainAdjust); + } + + uint32_t offset = 0U; + int16_t mask = 0x0800; + + for (uint32_t i = 0U; i < 12U; i++, mask >>= 1, offset++) + WRITE_BIT(codeword, offset, (frame_vector[0U] & mask) != 0); + + mask = 0x0800; + for (uint32_t i = 0U; i < 12U; i++, mask >>= 1, offset++) + WRITE_BIT(codeword, offset, (frame_vector[1U] & mask) != 0); + + mask = 0x0800; + for (uint32_t i = 0U; i < 12U; i++, mask >>= 1, offset++) + WRITE_BIT(codeword, offset, (frame_vector[2U] & mask) != 0); + + mask = 0x0800; + for (uint32_t i = 0U; i < 12U; i++, mask >>= 1, offset++) + WRITE_BIT(codeword, offset, (frame_vector[3U] & mask) != 0); + + mask = 0x0400; + for (uint32_t i = 0U; i < 11U; i++, mask >>= 1, offset++) + WRITE_BIT(codeword, offset, (frame_vector[4U] & mask) != 0); + + mask = 0x0400; + for (uint32_t i = 0U; i < 11U; i++, mask >>= 1, offset++) + WRITE_BIT(codeword, offset, (frame_vector[5U] & mask) != 0); + + mask = 0x0400; + for (uint32_t i = 0U; i < 11U; i++, mask >>= 1, offset++) + WRITE_BIT(codeword, offset, (frame_vector[6U] & mask) != 0); + + mask = 0x0040; + for (uint32_t i = 0U; i < 7U; i++, mask >>= 1, offset++) + WRITE_BIT(codeword, offset, (frame_vector[7U] & mask) != 0); + } + else { + int b[9]; + + // halfrate audio encoding - output rate is 2450 (49 bits) + encodeAMBE(m_vocoder.param(), b, &m_curMBEParms, &m_prevMBEParms, m_gainAdjust); + + uint8_t bits[49U]; + ::memset(bits, 0x00U, 49U); + + encode49bit(bits, b); + + // build 49-bit AMBE bytes + uint8_t rawAmbe[9U]; + ::memset(rawAmbe, 0x00U, 9U); + + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 8; ++j) { + rawAmbe[i] |= (bits[(i * 8) + j] << (7 - j)); + } + } + + // build DMR AMBE bytes + uint8_t dmrAMBE[9U]; + ::memset(dmrAMBE, 0x00U, 9U); + + encodeDmrAMBE(rawAmbe, dmrAMBE); + ::memcpy(codeword, dmrAMBE, 9U); + } +} diff --git a/vocoder/MBEEncoder.h b/vocoder/MBEEncoder.h new file mode 100644 index 0000000..9f2fda9 --- /dev/null +++ b/vocoder/MBEEncoder.h @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - MBE Vocoder + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright (C) 2019-2021 Doug McLain + * Copyright (C) 2021 Bryan Biedenkapp, N2PLL + * + */ +/** + * @file MBEEncoder.h + * @ingroup vocoder + * @file MBEEncoder.cpp + * @ingroup vocoder + */ +#if !defined(__MBE_ENCODER_H__) +#define __MBE_ENCODER_H__ + +#include "Defines.h" +#include "mbe.h" +#include "imbe/imbe_vocoder.h" + +#include + +namespace vocoder +{ + // --------------------------------------------------------------------------- + // Constants + // --------------------------------------------------------------------------- + + /** + * @brief Vocoder Encoding Mode + */ + enum MBE_ENCODER_MODE { + ENCODE_DMR_AMBE, //! DMR AMBE + ENCODE_88BIT_IMBE, //! 88-bit IMBE (P25) + }; + + // --------------------------------------------------------------------------- + // Class Declaration + // --------------------------------------------------------------------------- + + /** + * @brief Implements MBE audio encoding. + */ + class HOST_SW_API MBEEncoder { + public: + /** + * @brief Initializes a new instance of the MBEEncoder class. + * @param mode Encoder mode. + */ + MBEEncoder(MBE_ENCODER_MODE mode); + + /** + * @brief Encodes the given MBE bits to deinterleaved MBE bits using the encoder mode. + * @param[in] bits + * @param[out] codeword + */ + void encodeBits(uint8_t* bits, uint8_t* codeword); + + /** + * @brief Encodes the given PCM samples using the encoder mode to MBE codewords. + * @param[in] samples PCM samples (in short format) + * @param[out] codeword MBE codewords. + */ + void encode(int16_t* samples, uint8_t* codeword); + + private: + imbe_vocoder m_vocoder; + mbe_parms m_curMBEParms; + mbe_parms m_prevMBEParms; + + MBE_ENCODER_MODE m_mbeMode; + + public: + /** + * @brief Gain adjustment. + */ + __PROPERTY(float, gainAdjust, GainAdjust); + }; +} // namespace vocoder + +#endif // __MBE_ENCODER_H__ diff --git a/vocoder/Utils.cpp b/vocoder/Utils.cpp new file mode 100644 index 0000000..31ed237 --- /dev/null +++ b/vocoder/Utils.cpp @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - Common Library + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright (C) 2009,2014,2015,2016 Jonathan Naylor, G4KLX + * Copyright (C) 2018-2024 Bryan Biedenkapp, N2PLL + * + */ +#include "Utils.h" + +#include +#include + +#if defined(_WIN32) +#include +#endif // defined(_WIN32) + +// --------------------------------------------------------------------------- +// Constants/Macros +// --------------------------------------------------------------------------- + +const uint8_t BITS_TABLE[] = { +# define B2(n) n, n+1, n+1, n+2 +# define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2) +# define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2) + B6(0), B6(1), B6(1), B6(2) +}; + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +#if defined(_WIN32) +/* IP address from uint32_t value. */ + +uint32_t __IP_FROM_STR(const std::string& value) +{ + struct sockaddr_in sa; + inet_pton(AF_INET, value.c_str(), &(sa.sin_addr)); + + uint8_t ip[4U]; + ::memset(ip, 0x00U, 4U); + + ip[3U] = ((uint32_t)sa.sin_addr.s_addr >> 24) & 0xFFU; + ip[2U] = ((uint32_t)sa.sin_addr.s_addr >> 16) & 0xFFU; + ip[1U] = ((uint32_t)sa.sin_addr.s_addr >> 8) & 0xFFU; + ip[0U] = ((uint32_t)sa.sin_addr.s_addr >> 0) & 0xFFU; + + return (ip[0U] << 24) | (ip[1U] << 16) | (ip[2U] << 8) | (ip[3U] << 0); +} +#endif // defined(_WIN32) + +// --------------------------------------------------------------------------- +// Static Class Members +// --------------------------------------------------------------------------- + +/* Helper to convert the input byte to a boolean array of bits in big-endian. */ + +void Utils::byteToBitsBE(uint8_t byte, bool* bits) +{ + assert(bits != nullptr); + + bits[0U] = (byte & 0x80U) == 0x80U; + bits[1U] = (byte & 0x40U) == 0x40U; + bits[2U] = (byte & 0x20U) == 0x20U; + bits[3U] = (byte & 0x10U) == 0x10U; + bits[4U] = (byte & 0x08U) == 0x08U; + bits[5U] = (byte & 0x04U) == 0x04U; + bits[6U] = (byte & 0x02U) == 0x02U; + bits[7U] = (byte & 0x01U) == 0x01U; +} + +/* Helper to convert the input byte to a boolean array of bits in little-endian. */ + +void Utils::byteToBitsLE(uint8_t byte, bool* bits) +{ + assert(bits != nullptr); + + bits[0U] = (byte & 0x01U) == 0x01U; + bits[1U] = (byte & 0x02U) == 0x02U; + bits[2U] = (byte & 0x04U) == 0x04U; + bits[3U] = (byte & 0x08U) == 0x08U; + bits[4U] = (byte & 0x10U) == 0x10U; + bits[5U] = (byte & 0x20U) == 0x20U; + bits[6U] = (byte & 0x40U) == 0x40U; + bits[7U] = (byte & 0x80U) == 0x80U; +} + +/* Helper to convert the input boolean array of bits to a byte in big-endian. */ + +void Utils::bitsToByteBE(const bool* bits, uint8_t& byte) +{ + assert(bits != nullptr); + + byte = bits[0U] ? 0x80U : 0x00U; + byte |= bits[1U] ? 0x40U : 0x00U; + byte |= bits[2U] ? 0x20U : 0x00U; + byte |= bits[3U] ? 0x10U : 0x00U; + byte |= bits[4U] ? 0x08U : 0x00U; + byte |= bits[5U] ? 0x04U : 0x00U; + byte |= bits[6U] ? 0x02U : 0x00U; + byte |= bits[7U] ? 0x01U : 0x00U; +} + +/* Helper to convert the input boolean array of bits to a byte in little-endian. */ + +void Utils::bitsToByteLE(const bool* bits, uint8_t& byte) +{ + assert(bits != nullptr); + + byte = bits[0U] ? 0x01U : 0x00U; + byte |= bits[1U] ? 0x02U : 0x00U; + byte |= bits[2U] ? 0x04U : 0x00U; + byte |= bits[3U] ? 0x08U : 0x00U; + byte |= bits[4U] ? 0x10U : 0x00U; + byte |= bits[5U] ? 0x20U : 0x00U; + byte |= bits[6U] ? 0x40U : 0x00U; + byte |= bits[7U] ? 0x80U : 0x00U; +} + +/* Helper to reverse the endianness of the passed value. */ + +uint16_t Utils::reverseEndian(uint16_t value) +{ + return (value << 8 & 0xff00) | (value >> 8); +} + +/* Helper to reverse the endianness of the passed value. */ + +uint32_t Utils::reverseEndian(uint32_t value) +{ + return (value << 24 | (value & 0xFF00U) << 8 | (value & 0xFF0000U) >> 8 | value >> 24); +} + +/* Helper to reverse the endianness of the passed value. */ + +uint64_t Utils::reverseEndian(uint64_t value) +{ + return (value << 56 | (value & 0xFF00U) << 40 | (value & 0xFF0000U) << 24 | (value & 0xFF000000U) << 8 | + (value & 0xFF00000000U) >> 8 | (value & 0xFF0000000000U) >> 24 | (value & 0xFF000000000000U) >> 40 | value >> 56); +} + +/* Helper to retreive arbitrary length of bits from an input buffer. */ + +uint32_t Utils::getBits(const uint8_t* in, uint8_t* out, uint32_t start, uint32_t stop) +{ + assert(in != nullptr); + assert(out != nullptr); + + uint32_t n = 0U; + for (uint32_t i = start; i < stop; i++, n++) { + bool b = READ_BIT(in, i); + WRITE_BIT(out, n, b); + } + + return n; +} + +/* Helper to retreive arbitrary length of bits from an input buffer. */ + +uint32_t Utils::getBitRange(const uint8_t* in, uint8_t* out, uint32_t start, uint32_t length) +{ + return getBits(in, out, start, start + length); +} + +/* Helper to set an arbitrary length of bits from an input buffer. */ + +uint32_t Utils::setBits(const uint8_t* in, uint8_t* out, uint32_t start, uint32_t stop) +{ + assert(in != nullptr); + assert(out != nullptr); + + uint32_t n = 0U; + for (uint32_t i = start; i < stop; i++, n++) { + bool b = READ_BIT(in, n); + WRITE_BIT(out, i, b); + } + + return n; +} + +/* Helper to set an arbitrary length of bits from an input buffer. */ + +uint32_t Utils::setBitRange(const uint8_t* in, uint8_t* out, uint32_t start, uint32_t length) +{ + return setBits(in, out, start, start + length); +} + +/* Helper to convert a binary input buffer into representative 6-bit byte. */ + +uint8_t Utils::bin2Hex(const uint8_t* input, uint32_t offset) +{ + uint8_t output = 0x00U; + + output |= READ_BIT(input, offset + 0U) ? 0x20U : 0x00U; + output |= READ_BIT(input, offset + 1U) ? 0x10U : 0x00U; + output |= READ_BIT(input, offset + 2U) ? 0x08U : 0x00U; + output |= READ_BIT(input, offset + 3U) ? 0x04U : 0x00U; + output |= READ_BIT(input, offset + 4U) ? 0x02U : 0x00U; + output |= READ_BIT(input, offset + 5U) ? 0x01U : 0x00U; + + return output; +} + +/* Helper to convert 6-bit input byte into representative binary buffer. */ + +void Utils::hex2Bin(const uint8_t input, uint8_t* output, uint32_t offset) +{ + WRITE_BIT(output, offset + 0U, input & 0x20U); + WRITE_BIT(output, offset + 1U, input & 0x10U); + WRITE_BIT(output, offset + 2U, input & 0x08U); + WRITE_BIT(output, offset + 3U, input & 0x04U); + WRITE_BIT(output, offset + 4U, input & 0x02U); + WRITE_BIT(output, offset + 5U, input & 0x01U); +} + +/* Returns the count of bits in the passed 8 byte value. */ + +uint8_t Utils::countBits8(uint8_t bits) +{ + return BITS_TABLE[bits]; +} + +/* Returns the count of bits in the passed 32 byte value. */ + +uint8_t Utils::countBits32(uint32_t bits) +{ + uint8_t* p = (uint8_t*)&bits; + uint8_t n = 0U; + n += BITS_TABLE[p[0U]]; + n += BITS_TABLE[p[1U]]; + n += BITS_TABLE[p[2U]]; + n += BITS_TABLE[p[3U]]; + return n; +} + +/* Returns the count of bits in the passed 64 byte value. */ + +uint8_t Utils::countBits64(ulong64_t bits) +{ + uint8_t* p = (uint8_t*)&bits; + uint8_t n = 0U; + n += BITS_TABLE[p[0U]]; + n += BITS_TABLE[p[1U]]; + n += BITS_TABLE[p[2U]]; + n += BITS_TABLE[p[3U]]; + n += BITS_TABLE[p[4U]]; + n += BITS_TABLE[p[5U]]; + n += BITS_TABLE[p[6U]]; + n += BITS_TABLE[p[7U]]; + return n; +} diff --git a/vocoder/Utils.h b/vocoder/Utils.h new file mode 100644 index 0000000..3254c74 --- /dev/null +++ b/vocoder/Utils.h @@ -0,0 +1,432 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - Common Library + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright (C) 2009,2014,2015 Jonathan Naylor, G4KLX + * Copyright (C) 2018-2024 Bryan Biedenkapp, N2PLL + * + */ +/** + * @defgroup utils Utility Routines + * @brief Defines and implements utility routines. + * @ingroup common + * + * @file Utils.h + * @ingroup utils + * @file Utils.cpp + * @ingroup utils + */ +#if !defined(__UTILS_H__) +#define __UTILS_H__ + +#include "Defines.h" + +#include +#include + +#if !defined(_WIN32) +#include +#endif // !defined(WIN32) + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +/** + * @brief Bit mask table used for WRITE_BIT and READ_BIT. + * @ingroup utils + */ +const uint8_t BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; + +// --------------------------------------------------------------------------- +// Inlines +// --------------------------------------------------------------------------- + +/** + * @brief String from boolean. + * @ingroup utils + * @param value Boolean value to convert. + * @return std::string String representation of the boolean value. + */ +inline std::string __BOOL_STR(const bool& value) { + std::stringstream ss; + ss << std::boolalpha << value; + return ss.str(); +} + +/** + * @brief String from integer number. + * @ingroup utils + * @param value Integer value to convert. + * @return std::string String representation of the integer value. + */ +inline std::string __INT_STR(const int& value) { + std::stringstream ss; + ss << value; + return ss.str(); +} + +/** + * @brief String from hex integer number. + * @ingroup utils + * @param value Integer value to convert. + * @return std::string String representation of the integer value in hexadecmial. + */ +inline std::string __INT_HEX_STR(const int& value) { + std::stringstream ss; + ss << std::hex << value; + return ss.str(); +} + +/** + * @brief String from floating point number. + * @ingroup utils + * @param value Floating point value to convert. + * @return std::string String representation of the floating point value. + */ +inline std::string __FLOAT_STR(const float& value) { + std::stringstream ss; + ss << value; + return ss.str(); +} + +/** + * @brief IP address from uint32_t value. + * @ingroup utils + * @param value Packed IP address. + * @return std::string String representation of the packed IP address. + */ +inline std::string __IP_FROM_UINT(const uint32_t& value) { + std::stringstream ss; + ss << ((value >> 24) & 0xFFU) << "." << ((value >> 16) & 0xFFU) << "." << ((value >> 8) & 0xFFU) << "." << (value & 0xFFU); + return ss.str(); +} + +/** + * @brief IP address from uint32_t value. + * @ingroup utils + * @param value String representation of the IP address. + * @return uint32_t Packed IP address. + */ +#if !defined(_WIN32) +inline uint32_t __IP_FROM_STR(const std::string& value) { + struct sockaddr_in sa; + inet_pton(AF_INET, value.c_str(), &(sa.sin_addr)); + + uint8_t ip[4U]; + ::memset(ip, 0x00U, 4U); + + ip[3U] = ((uint32_t)sa.sin_addr.s_addr >> 24) & 0xFFU; + ip[2U] = ((uint32_t)sa.sin_addr.s_addr >> 16) & 0xFFU; + ip[1U] = ((uint32_t)sa.sin_addr.s_addr >> 8) & 0xFFU; + ip[0U] = ((uint32_t)sa.sin_addr.s_addr >> 0) & 0xFFU; + + return (ip[0U] << 24) | (ip[1U] << 16) | (ip[2U] << 8) | (ip[3U] << 0); +} +#else +extern HOST_SW_API uint32_t __IP_FROM_STR(const std::string& value); +#endif // !defined(_WIN32) + +/** + * @brief Helper to lower-case an input string. + * @ingroup utils + * @param value String to lower-case. + * @return std::string Lowercased string. + */ +inline std::string strtolower(const std::string value) { + std::string v = value; + std::transform(v.begin(), v.end(), v.begin(), ::tolower); + return v; +} + +/** + * @brief Helper to upper-case an input string. + * @ingroup utils + * @param value String to upper-case. + * @return std::string Uppercased string. + */ +inline std::string strtoupper(const std::string value) { + std::string v = value; + std::transform(v.begin(), v.end(), v.begin(), ::toupper); + return v; +} + +// --------------------------------------------------------------------------- +// Macros +// --------------------------------------------------------------------------- + +/** + * @brief Pointer magic to get the memory address of a floating point number. + * @ingroup utils + * @param x Floating Point Variable + */ +#define __FLOAT_ADDR(x) (*(uint32_t*)& x) +/** + * @brief Pointer magic to get the memory address of a double precision number. + * @ingroup utils + * @param x Double Precision Variable + */ +#define __DOUBLE_ADDR(x) (*(uint64_t*)& x) + +/** + * @brief Macro helper to write a specific bit in a byte array. + * @ingroup utils + * @param p Byte array. + * @param i Bit offset. + * @param b Bit to write. + */ +#define WRITE_BIT(p, i, b) p[(i) >> 3] = (b) ? (p[(i) >> 3] | BIT_MASK_TABLE[(i) & 7]) : (p[(i) >> 3] & ~BIT_MASK_TABLE[(i) & 7]) +/** + * @brief Macro helper to read a specific bit from a byte array. + * @ingroup utils + * @param p Byte array. + * @param i Bit offset. + * @returns bool Bit. + */ +#define READ_BIT(p, i) (p[(i) >> 3] & BIT_MASK_TABLE[(i) & 7]) + +/** + * @brief Sets a uint32_t into 4 bytes. + * @ingroup utils + * @param val uint32_t value to set + * @param buffer uint8_t buffer to set value on + * @param offset Offset within uint8_t buffer + */ +#define __SET_UINT32(val, buffer, offset) \ + buffer[0U + offset] = (val >> 24) & 0xFFU; \ + buffer[1U + offset] = (val >> 16) & 0xFFU; \ + buffer[2U + offset] = (val >> 8) & 0xFFU; \ + buffer[3U + offset] = (val >> 0) & 0xFFU; +/** + * @brief Gets a uint32_t consisting of 4 bytes. + * @ingroup utils + * @param buffer uint8_t buffer to get value from + * @param offset Offset within uint8_t buffer + */ +#define __GET_UINT32(buffer, offset) \ + (buffer[offset + 0U] << 24) | \ + (buffer[offset + 1U] << 16) | \ + (buffer[offset + 2U] << 8) | \ + (buffer[offset + 3U] << 0); +/** + * @brief Sets a uint32_t into 3 bytes. + * @ingroup utils + * @param val uint32_t value to set + * @param buffer uint8_t buffer to set value on + * @param offset Offset within uint8_t buffer + */ +#define __SET_UINT16(val, buffer, offset) \ + buffer[0U + offset] = (val >> 16) & 0xFFU; \ + buffer[1U + offset] = (val >> 8) & 0xFFU; \ + buffer[2U + offset] = (val >> 0) & 0xFFU; +/** + * @brief Gets a uint32_t consisting of 3 bytes. (This is a shortened uint32_t). + * @ingroup utils + * @param buffer uint8_t buffer to get value from + * @param offset Offset within uint8_t buffer + */ +#define __GET_UINT16(buffer, offset) \ + (buffer[offset + 0U] << 16) | \ + (buffer[offset + 1U] << 8) | \ + (buffer[offset + 2U] << 0); +/** + * @brief Sets a uint16_t into 2 bytes. + * @ingroup utils + * @param val uint16_t value to set + * @param buffer uint8_t buffer to set value on + * @param offset Offset within uint8_t buffer + */ +#define __SET_UINT16B(val, buffer, offset) \ + buffer[0U + offset] = (val >> 8) & 0xFFU; \ + buffer[1U + offset] = (val >> 0) & 0xFFU; +/** + * @brief Gets a uint16_t consisting of 2 bytes. + * @ingroup utils + * @param buffer uint8_t buffer to get value from + * @param offset Offset within uint8_t buffer + */ +#define __GET_UINT16B(buffer, offset) \ + ((buffer[offset + 0U] << 8) & 0xFF00U) | \ + ((buffer[offset + 1U] << 0) & 0x00FFU); + +/** + * @brief Unique uint8_t array. + * @ingroup utils + */ +typedef std::unique_ptr UInt8Array; +/** + * @brief Unique char array. + * @ingroup utils + */ +typedef std::unique_ptr CharArray; + +// --------------------------------------------------------------------------- +// Class Declaration +// --------------------------------------------------------------------------- + +/** + * @brief Various helper utilities. + * @ingroup utils + */ +class HOST_SW_API Utils { +public: + /** + * @brief Helper to dump the input buffer and display the hexadecimal output in the log. + * @param title Name of buffer. + * @param data Buffer to dump. + * @param length Length of buffer. + */ + static void dump(const std::string& title, const uint8_t* data, uint32_t length); + /** + * @brief Helper to dump the input buffer and display the hexadecimal output in the log. + * @param level Log level. + * @param title Name of buffer. + * @param data Buffer to dump. + * @param length Length of buffer. + */ + static void dump(int level, const std::string& title, const uint8_t* data, uint32_t length); + + /** + * @brief Helper to dump the input boolean bit buffer and display the hexadecimal output in the log. + * @param title Name of buffer. + * @param data Buffer to dump. + * @param length Length of buffer. + */ + static void dump(const std::string& title, const bool* bits, uint32_t length); + /** + * @brief Helper to dump the input boolean bit buffer and display the hexadecimal output in the log. + * @param level Log level. + * @param title Name of buffer. + * @param data Buffer to dump. + * @param length Length of buffer. + */ + static void dump(int level, const std::string& title, const bool* bits, uint32_t length); + + /** + * @brief Helper to dump the input buffer and display the output as a symbolic microslot output. + * @param title Name of buffer. + * @param data Buffer to dump. + * @param length Length of buffer. + */ + static void symbols(const std::string& title, const uint8_t* data, uint32_t length); + + /** + * @brief Helper to convert the input byte to a boolean array of bits in big-endian. + * @param byte Input byte. + * @param bits Output bits array. + */ + static void byteToBitsBE(uint8_t byte, bool* bits); + /** + * @brief Helper to convert the input byte to a boolean array of bits in little-endian. + * @param byte Input byte. + * @param bits Output bits array. + */ + static void byteToBitsLE(uint8_t byte, bool* bits); + + /** + * @brief Helper to convert the input boolean array of bits to a byte in big-endian. + * @param byte Input bits array. + * @param bits Output byte. + */ + static void bitsToByteBE(const bool* bits, uint8_t& byte); + /** + * @brief Helper to convert the input boolean array of bits to a byte in little-endian. + * @param byte Input bits array. + * @param bits Output byte. + */ + static void bitsToByteLE(const bool* bits, uint8_t& byte); + + /** + * @brief Helper to reverse the endianness of the passed value. + * @param value Value to reverse. + * @returns uint16_t Endian reversed output. + */ + static uint16_t reverseEndian(uint16_t value); + /** + * @brief Helper to reverse the endianness of the passed value. + * @param value Value to reverse. + * @returns uint32_t Endian reversed output. + */ + static uint32_t reverseEndian(uint32_t value); + /** + * @brief Helper to reverse the endianness of the passed value. + * @param value Value to reverse. + * @returns uint64_t Endian reversed output. + */ + static uint64_t reverseEndian(uint64_t value); + + /** + * @brief Helper to retreive arbitrary length of bits from an input buffer. + * @param in Input buffer. + * @param out Output buffer. + * @param start Starting bit offset in input buffer to read from. + * @param stop Ending bit offset in input buffer to stop reading. + * @returns uint32_t Count of bits read. + */ + static uint32_t getBits(const uint8_t* in, uint8_t* out, uint32_t start, uint32_t stop); + /** + * @brief Helper to retreive arbitrary length of bits from an input buffer. + * @param in Input buffer. + * @param out Output buffer. + * @param start Starting bit offset in input buffer to read from. + * @param length Number of bits to read. + * @returns uint32_t Count of bits read. + */ + static uint32_t getBitRange(const uint8_t* in, uint8_t* out, uint32_t start, uint32_t length); + /** + * @brief Helper to set an arbitrary length of bits from an input buffer. + * @param in Input buffer. + * @param out Output buffer. + * @param start Starting bit offset in input buffer to read from. + * @param stop Ending bit offset in input buffer to stop reading. + * @returns uint32_t Count of bits set. + */ + static uint32_t setBits(const uint8_t* in, uint8_t* out, uint32_t start, uint32_t stop); + /** + * @brief Helper to set arbitrary length of bits from an input buffer. + * @param in Input buffer. + * @param out Output buffer. + * @param start Starting bit offset in input buffer to read from. + * @param length Number of bits to set. + * @returns uint32_t Count of bits set. + */ + static uint32_t setBitRange(const uint8_t* in, uint8_t* out, uint32_t start, uint32_t length); + + /** + * @brief Helper to convert a binary input buffer into representative 6-bit byte. + * @param input Input buffer. + * @param offset Buffer offset. + * @returns uint8_t Representative 6-bit output. + */ + static uint8_t bin2Hex(const uint8_t* input, uint32_t offset); + /** + * @brief Helper to convert 6-bit input byte into representative binary buffer. + * @param input Input 6-bit byte. + * @param output Output buffer. + * @param offset Buffer offset. + */ + static void hex2Bin(const uint8_t input, uint8_t* output, uint32_t offset); + + /** + * @brief Returns the count of bits in the passed 8 byte value. + * @param bits uint8_t to count bits for. + * @returns uint8_t Count of bits in passed value. + */ + static uint8_t countBits8(uint8_t bits); + /** + * @brief Returns the count of bits in the passed 32 byte value. + * @param bits uint32_t to count bits for. + * @returns uint8_t Count of bits in passed value. + */ + static uint8_t countBits32(uint32_t bits); + /** + * @brief Returns the count of bits in the passed 64 byte value. + * @param bits ulong64_t to count bits for. + * @returns uint8_t Count of bits in passed value. + */ + static uint8_t countBits64(ulong64_t bits); +}; + +#endif // __UTILS_H__ diff --git a/vocoder/ambe3600x2250.c b/vocoder/ambe3600x2250.c new file mode 100644 index 0000000..51153b5 --- /dev/null +++ b/vocoder/ambe3600x2250.c @@ -0,0 +1,404 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - MBE Vocoder + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + */ + +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#define _USE_MATH_DEFINES +#include + +#include "mbe.h" + +#ifdef _MSC_VER +#pragma warning(disable: 4244) +#pragma warning(disable: 4305) +#endif +#if defined(__GNUC__) || defined(__GNUG__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#endif + +// --------------------------------------------------------------------------- +// Externs +// --------------------------------------------------------------------------- + +/* +** these are all declared by include in ambe3600x2450.c +*/ +extern const float AmbeW0table[120]; +extern const float AmbeLtable[120]; +extern const int AmbeVuv[32][8]; +extern const int AmbeLmprbl[57][4]; +extern const float AmbeDg[32]; +extern const float AmbePRBA24[512][3]; +extern const float AmbePRBA58[128][4]; +extern const float AmbeHOCb5[32][4]; +extern const float AmbeHOCb6[16][4]; +extern const float AmbeHOCb7[16][4]; +extern const float AmbeHOCb8[8][4]; + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +/* */ + +int mbe_dequantizeAmbe2250Parms(mbe_parms* cur_mp, mbe_parms* prev_mp, const int* b) +{ + int ji, i, j, k, l, L, m, am, ak; + int intkl[57]; + int b0, b1, b2, b3, b4, b5, b6, b7, b8; + float f0, Cik[5][18], flokl[57], deltal[57]; + float Sum42, Sum43, Tl[57], Gm[9], Ri[9], sum, c1, c2; + //char tmpstr[13]; + int silence; + int Ji[5], jl; + float deltaGamma, BigGamma; + float unvc, rconst; + + b0 = b[0]; + b1 = b[1]; + b2 = b[2]; + b3 = b[3]; + b4 = b[4]; + b5 = b[5]; + b6 = b[6]; + b7 = b[7]; + b8 = b[8]; + + silence = 0; + + // copy repeat from prev_mp + cur_mp->repeat = prev_mp->repeat; + + if ((b0 >= 120) && (b0 <= 123)) { +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: Erasure Frame"); +#endif + return (2); + } + else if ((b0 == 124) || (b0 == 125)) { +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: Silence Frame"); +#endif + silence = 1; + cur_mp->w0 = ((float)2 * M_PI) / (float)32; + f0 = (float)1 / (float)32; + L = 14; + cur_mp->L = 14; + for (l = 1; l <= L; l++) + { + cur_mp->Vl[l] = 0; + } + } + else if ((b0 == 126) || (b0 == 127)) { +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: Tone Frame"); +#endif + return (3); + } + + if (silence == 0) { + // w0 from specification document + f0 = AmbeW0table[b0]; + cur_mp->w0 = f0 * (float)2 * M_PI; + // w0 from patent filings + //f0 = powf (2, ((float) b0 + (float) 195.626) / -(float) 45.368); + //cur_mp->w0 = f0 * (float) 2 *M_PI; + } + + unvc = (float)0.2046 / sqrtf(cur_mp->w0); + //unvc = (float) 1; + //unvc = (float) 0.2046 / sqrtf (f0); + + // decode L + if (silence == 0) { + // L from specification document + // lookup L in tabl3 + L = AmbeLtable[b0]; + // L formula form patent filings + //L=(int)((float)0.4627 / f0); + cur_mp->L = L; + } + + // decode V/UV parameters + for (l = 1; l <= L; l++) { + // jl from specification document + jl = (int)((float)l * (float)16.0 * f0); + // jl from patent filings? + //jl = (int)(((float)l * (float)16.0 * f0) + 0.25); + + if (silence == 0) { + cur_mp->Vl[l] = AmbeVuv[b1][jl]; + } +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: jl[%i]:%i Vl[%i]:%i", l, jl, l, cur_mp->Vl[l]); +#endif + } + +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: b0:%i w0:%f L:%i b1:%i", b0, cur_mp->w0, L, b1); +#endif + + deltaGamma = AmbeDg[b2]; + cur_mp->gamma = deltaGamma + ((float)0.5 * prev_mp->gamma); + +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: b2: %i, deltaGamma: %f gamma: %f gamma-1: %f", b2, deltaGamma, cur_mp->gamma, prev_mp->gamma); +#endif + + // decode PRBA vectors + Gm[1] = 0; + Gm[2] = AmbePRBA24[b3][0]; + Gm[3] = AmbePRBA24[b3][1]; + Gm[4] = AmbePRBA24[b3][2]; + + Gm[5] = AmbePRBA58[b4][0]; + Gm[6] = AmbePRBA58[b4][1]; + Gm[7] = AmbePRBA58[b4][2]; + Gm[8] = AmbePRBA58[b4][3]; + +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: b3: %i Gm[2]: %f Gm[3]: %f Gm[4]: %f b4: %i Gm[5]: %f Gm[6]: %f Gm[7]: %f Gm[8]: %f", b3, Gm[2], Gm[3], Gm[4], b4, Gm[5], Gm[6], Gm[7], Gm[8]); +#endif + + // compute Ri + for (i = 1; i <= 8; i++) { + sum = 0; + for (m = 1; m <= 8; m++) { + if (m == 1) { + am = 1; + } + else { + am = 2; + } + sum = sum + ((float)am * Gm[m] * cosf((M_PI * (float)(m - 1) * ((float)i - (float)0.5)) / (float)8)); + } + + Ri[i] = sum; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: R%i: %f", i, Ri[i]); +#endif + } + + // generate first to elements of each Ci,k block from PRBA vector + rconst = ((float)1 / ((float)2 * M_SQRT2)); + Cik[1][1] = (float)0.5 * (Ri[1] + Ri[2]); + Cik[1][2] = rconst * (Ri[1] - Ri[2]); + Cik[2][1] = (float)0.5 * (Ri[3] + Ri[4]); + Cik[2][2] = rconst * (Ri[3] - Ri[4]); + Cik[3][1] = (float)0.5 * (Ri[5] + Ri[6]); + Cik[3][2] = rconst * (Ri[5] - Ri[6]); + Cik[4][1] = (float)0.5 * (Ri[7] + Ri[8]); + Cik[4][2] = rconst * (Ri[7] - Ri[8]); + + // decode HOC + + // lookup Ji + Ji[1] = AmbeLmprbl[L][0]; + Ji[2] = AmbeLmprbl[L][1]; + Ji[3] = AmbeLmprbl[L][2]; + Ji[4] = AmbeLmprbl[L][3]; + +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: Ji[1]: %i Ji[2]: %i Ji[3]: %i Ji[4]: %i", Ji[1], Ji[2], Ji[3], Ji[4]); + fprintf(stderr, "MBE: AMBE: b5: %i b6: %i b7: %i b8: %i", b5, b6, b7, b8); +#endif + + // Load Ci,k with the values from the HOC tables + // there appear to be a couple typos in eq. 37 so we will just do what makes sense + // (3 <= k <= Ji and k<=6) + for (k = 3; k <= Ji[1]; k++) { + if (k > 6) { + Cik[1][k] = 0; + } + else { + Cik[1][k] = AmbeHOCb5[b5][k - 3]; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: C1,%i: %f", k, Cik[1][k]); +#endif + } + } + + for (k = 3; k <= Ji[2]; k++) { + if (k > 6) { + Cik[2][k] = 0; + } + else { + Cik[2][k] = AmbeHOCb6[b6][k - 3]; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: C2,%i: %f", k, Cik[2][k]); +#endif + } + } + + for (k = 3; k <= Ji[3]; k++) { + if (k > 6) { + Cik[3][k] = 0; + } + else { + Cik[3][k] = AmbeHOCb7[b7][k - 3]; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: C3,%i: %f", k, Cik[3][k]); +#endif + } + } + + for (k = 3; k <= Ji[4]; k++) { + if (k > 6) { + Cik[4][k] = 0; + } + else { + Cik[4][k] = AmbeHOCb8[b8][k - 3]; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: C4,%i: %f", k, Cik[4][k]); +#endif + } + } + + // inverse DCT each Ci,k to give ci,j (Tl) + l = 1; + for (i = 1; i <= 4; i++) { + ji = Ji[i]; + for (j = 1; j <= ji; j++) { + sum = 0; + for (k = 1; k <= ji; k++) { + if (k == 1) { + ak = 1; + } + else { + ak = 2; + } +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: %i Cik[%i][%i]: %f", j, i, k, Cik[i][k]); +#endif + sum = sum + ((float)ak * Cik[i][k] * cosf((M_PI * (float)(k - 1) * ((float)j - (float)0.5)) / (float)ji)); + } + Tl[l] = sum; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: Tl[%i]: %f", l, Tl[l]); +#endif + l++; + } + } + + // determine log2Ml by applying ci,j to previous log2Ml + + // fix for when L > L(-1) + if (cur_mp->L > prev_mp->L) { + for (l = (prev_mp->L) + 1; l <= cur_mp->L; l++) { + prev_mp->Ml[l] = prev_mp->Ml[prev_mp->L]; + prev_mp->log2Ml[l] = prev_mp->log2Ml[prev_mp->L]; + } + } + prev_mp->log2Ml[0] = prev_mp->log2Ml[1]; + prev_mp->Ml[0] = prev_mp->Ml[1]; + + // Part 1 + Sum43 = 0; + for (l = 1; l <= cur_mp->L; l++) { + // eq. 40 + flokl[l] = ((float)prev_mp->L / (float)cur_mp->L) * (float)l; + intkl[l] = (int)(flokl[l]); +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: flok%i: %f, intk%i: %i", l, flokl[l], l, intkl[l]); +#endif + // eq. 41 + deltal[l] = flokl[l] - (float)intkl[l]; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: delta%i: %f", l, deltal[l]); +#endif + // eq 43 + Sum43 = Sum43 + ((((float)1 - deltal[l]) * prev_mp->log2Ml[intkl[l]]) + (deltal[l] * prev_mp->log2Ml[intkl[l] + 1])); + } + + Sum43 = (((float)0.65 / (float)cur_mp->L) * Sum43); +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: Sum43: %f", Sum43); +#endif + + // Part 2 + Sum42 = 0; + for (l = 1; l <= cur_mp->L; l++) { + Sum42 += Tl[l]; + } + + Sum42 = Sum42 / (float)cur_mp->L; + BigGamma = cur_mp->gamma - ((float)0.5 * (log((float)cur_mp->L) / log((float)2))) - Sum42; + //BigGamma=cur_mp->gamma - ((float)0.5 * log((float)cur_mp->L)) - Sum42; + + // Part 3 + for (l = 1; l <= cur_mp->L; l++) { + c1 = ((float)0.65 * ((float)1 - deltal[l]) * prev_mp->log2Ml[intkl[l]]); + c2 = ((float)0.65 * deltal[l] * prev_mp->log2Ml[intkl[l] + 1]); + cur_mp->log2Ml[l] = Tl[l] + c1 + c2 - Sum43 + BigGamma; + // inverse log to generate spectral amplitudes + if (cur_mp->Vl[l] == 1) { + cur_mp->Ml[l] = exp((float)0.693 * cur_mp->log2Ml[l]); + } + else { + cur_mp->Ml[l] = unvc * exp((float)0.693 * cur_mp->log2Ml[l]); + } +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: flokl[%i]: %f, intkl[%i]: %i", l, flokl[l], l, intkl[l]); + fprintf(stderr, "MBE: AMBE: deltal[%i]: %f", l, deltal[l]); + fprintf(stderr, "MBE: AMBE: prev_mp->log2Ml[%i]: %f", l, prev_mp->log2Ml[intkl[l]]); + fprintf(stderr, "MBE: AMBE: BigGamma: %f c1: %f c2: %f Sum43: %f Tl[%i]: %f log2Ml[%i]: %f Ml[%i]: %f", BigGamma, c1, c2, Sum43, l, Tl[l], l, cur_mp->log2Ml[l], l, cur_mp->Ml[l]); +#endif + } + + return (0); +} + +/* */ + +int mbe_dequantizeAmbeTone(mbe_tone* tone, const int* u) +{ + int bitchk1, bitchk2; + int AD, ID1, ID2, ID3, ID4; + bitchk1 = (u[0] >> 6) & 0x3f; + bitchk2 = (u[3] & 0xf); + + if ((bitchk1 != 63) || (bitchk2 != 0)) + return -1; // Not a valid tone frame + + AD = ((u[0] & 0x3f) << 1) + ((u[3] >> 4) & 0x1); + ID1 = ((u[1] & 0xfff) >> 4); + ID2 = ((u[1] & 0xf) << 4) + ((u[2] >> 7) & 0xf); + ID3 = ((u[2] & 0x7f) << 1) + ((u[3] >> 13) & 0x1); + ID4 = ((u[3] & 0x1fe0) >> 5); + + if ((ID1 == ID2) && (ID1 == ID3) && (ID1 == ID4) && + (((ID1 >= 5) && (ID1 <= 122)) || ((ID1 >= 128) && (ID1 <= 163)) || (ID1 == 255))) { + if (tone->ID == ID1) { + tone->AD = AD; + } + else { + tone->n = 0; + tone->ID = ID1; + tone->AD = AD; + } + return 0; // valid in-range tone frequency + } + + return -1; +} diff --git a/vocoder/ambe3600x2400.c b/vocoder/ambe3600x2400.c new file mode 100644 index 0000000..df5d68a --- /dev/null +++ b/vocoder/ambe3600x2400.c @@ -0,0 +1,656 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - MBE Vocoder + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + */ + +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#define _USE_MATH_DEFINES +#include + +#include "mbe.h" +#include "ambe3600x2400_const.h" + +#ifdef _MSC_VER +#pragma warning(disable: 4244) +#endif +#if defined(__GNUC__) || defined(__GNUG__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#endif + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +/* */ + +int mbe_eccAmbe3600x2400C0(char ambe_fr[4][24]) +{ + int j, errs; + char in[23], out[23]; + + for (j = 0; j < 23; j++) { + in[j] = ambe_fr[0][j + 1]; + } + + errs = mbe_golay2312(in, out); + // ambe_fr[0][0] should be the C0 golay24 parity bit. + // TODO: actually test that here... + for (j = 0; j < 23; j++) { + ambe_fr[0][j + 1] = out[j]; + } + + return (errs); +} + +/* */ + +int mbe_eccAmbe3600x2400Data(char ambe_fr[4][24], char* ambe_d) +{ + int j, errs; + char* ambe, gin[24], gout[24]; + + ambe = ambe_d; + // just copy C0 + for (j = 23; j > 11; j--) { + *ambe = ambe_fr[0][j]; + ambe++; + } + + // ecc and copy C1 + for (j = 0; j < 23; j++) { + gin[j] = ambe_fr[1][j]; + } + + errs = mbe_golay2312(gin, gout); + for (j = 22; j > 10; j--) { + *ambe = gout[j]; + ambe++; + } + + // just copy C2 + for (j = 10; j >= 0; j--) { + *ambe = ambe_fr[2][j]; + ambe++; + } + + // just copy C3 + for (j = 13; j >= 0; j--) { + *ambe = ambe_fr[3][j]; + ambe++; + } + + return (errs); +} + +/* */ + +int mbe_decodeAmbe2400Parms(char* ambe_d, mbe_parms* cur_mp, mbe_parms* prev_mp) +{ + int ji, i, j, k, l, L, L9, m, am, ak; + int intkl[57]; + int b0, b1, b2, b3, b4, b5, b6, b7, b8; + float f0, Cik[5][18], flokl[57], deltal[57]; + float Sum42, Sum43, Tl[57], Gm[9], Ri[9], sum, c1, c2; + int silence; + int Ji[5], jl; + float deltaGamma, BigGamma; + float unvc, rconst; + + silence = 0; + + // copy repeat from prev_mp + cur_mp->repeat = prev_mp->repeat; + + // check if frame is tone or other; this matches section 7.2 on the P25 Half rate vocoder annex doc + b0 = 0; + b0 |= ambe_d[0] << 6; + b0 |= ambe_d[1] << 5; + b0 |= ambe_d[2] << 4; + b0 |= ambe_d[3] << 3; + b0 |= ambe_d[4] << 2; + b0 |= ambe_d[5] << 1; + b0 |= ambe_d[48]; + + if ((b0 & 0x7E) == 0x7E) { + // frame is tone + // find tone index + // Cx# 0000000000001111111111112222222222233333333333333 + // + // IDX 0000000000111111111122222222223333333333444444444 + // idx 0123456789012345678901234567890123456789012345678 + // exm 1111110101001110100000001000000000000000001100000 : t=0111100 + // ex2 1111110110101110100000000000000000000000000000000 : t=1100010 + // ex3 1111110010101110110000001000000000000000000110000 : t=0000110 + // tt1 1111110010011110100000001000000000000000000101000 : t=0000101 + // tt3 1111110010011110000000001000000000000000000101000 + // ton HHHHHHDEF410======......P.................32==... + // vol 765430 21 + //DEF indexes the following tables for tone bits 5-7 + int t7tab[8] = { 1,0,0,0,0,1,1,1 }; + int t6tab[8] = { 0,0,0,1,1,1,1,0 }; + int t5tab[8] = { 0,0,1,0,1,1,0,1 }; + // V V V V V G G G V = verified, G = guessed (and unused by all normal tone indices) + b1 = 0; + b1 |= t7tab[((ambe_d[6] << 2) | (ambe_d[7] << 1) | ambe_d[8])] << 7; //t7 128 + b1 |= t6tab[((ambe_d[6] << 2) | (ambe_d[7] << 1) | ambe_d[8])] << 6; //t6 64 + b1 |= t5tab[((ambe_d[6] << 2) | (ambe_d[7] << 1) | ambe_d[8])] << 5; //t5 32 + b1 |= ambe_d[9] << 4; //t4 16 e verified + b1 |= ambe_d[42] << 3; //t3 8 d verified + b1 |= ambe_d[43] << 2; //t2 4 c verified + b1 |= ambe_d[10] << 1; //t1 2 b verified + b1 |= ambe_d[11]; //t0 1 a verified + + b2 = 0; + b2 |= ambe_d[12] << 7; //v7 128 h verified + b2 |= ambe_d[13] << 6; //v6 64 g verified + b2 |= ambe_d[14] << 5; //v5 32 f verified + b2 |= ambe_d[15] << 4; //v4 16 e guess based on data + b2 |= ambe_d[16] << 3; //v3 8 d guess based on data + b2 |= ambe_d[44] << 2; //v2 4 c guess based on data + b2 |= ambe_d[45] << 1; //v1 2 b guess based on data + b2 |= ambe_d[17]; //v0 1 a guess based on data + // the order of the last 3 bits may really be 17,44,45 not 44,45,17 as above + + //fprintf(stderr, "Tone volume: %d; ", b2); + if (b1 < 5) { + fprintf(stderr, "MBE: AMBE: index: %d, was <5, invalid!", b1); + silence = 1; + } + else if ((b1 >= 5) && (b1 <= 122)) { + fprintf(stderr, "MBE: AMBE: index: %d, Single tone hz: %f", b1, (float)b1 * 31.25); + } + else if ((b1 > 122) && (b1 < 128)) { + fprintf(stderr, "MBE: AMBE: index: %d, was >122 and <128, invalid!", b1); + silence = 1; + } + else if ((b1 >= 128) && (b1 <= 163)) { + fprintf(stderr, "MBE: AMBE: index: %d, Dual tone?", b1); + // note: dual tone index is different on ambe(dstar) and ambe2+ + } + else { + fprintf(stderr, "MBE: AMBE: index: %d, was >163, invalid!", b1); + silence = 1; + } + + if (silence == 1) { +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: Silence Frame"); +#endif + cur_mp->w0 = ((float)2 * M_PI) / (float)32; + f0 = (float)1 / (float)32; + L = 14; + cur_mp->L = 14; + for (l = 1; l <= L; l++) { + cur_mp->Vl[l] = 0; + } + } + +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: Tone Frame"); +#endif + return (3); + } + + // decode fundamental frequency w0 from b0 is already done + if (silence == 0) { + // w0 from specification document + //f0 = AmbeW0table[b0]; + //cur_mp->w0 = f0 * (float) 2 *M_PI; + // w0 from patent filings + //f0 = powf (2, ((float) b0 + (float) 195.626) / -(float) 46.368); // was 45.368 + // w0 guess + f0 = powf(2, (-4.311767578125 - (2.1336e-2 * ((float)b0 + 0.5)))); + cur_mp->w0 = f0 * (float)2 * M_PI; + } + + unvc = (float)0.2046 / sqrtf(cur_mp->w0); + //unvc = (float) 1; + //unvc = (float) 0.2046 / sqrtf (f0); + + // decode L + if (silence == 0) { + // L from specification document + // lookup L in tabl3 + L = AmbePlusLtable[b0]; + // L formula from patent filings + //L=(int)((float)0.4627 / f0); + cur_mp->L = L; + } + L9 = L - 9; + + // decode V/UV parameters + // load b1 from ambe_d + //TODO: use correct table (i.e. 0x0000 0x0005 0x0050 0x0055 etc) + b1 = 0; + b1 |= ambe_d[38] << 3; + b1 |= ambe_d[39] << 2; + b1 |= ambe_d[40] << 1; + b1 |= ambe_d[41]; + + for (l = 1; l <= L; l++) { + // jl from specification document + jl = (int)((float)l * (float)16.0 * f0); + // jl from patent filings? + //jl = (int)(((float)l * (float)16.0 * f0) + 0.25); + + if (silence == 0) + { + cur_mp->Vl[l] = AmbePlusVuv[b1][jl]; + } +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: jl[%i]:%i Vl[%i]:%i", l, jl, l, cur_mp->Vl[l]); +#endif + } + +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: b0:%i w0:%f L:%i b1:%i", b0, cur_mp->w0, L, b1); +#endif + + // decode gain vector + // load b2 from ambe_d + b2 = 0; + b2 |= ambe_d[6] << 5; + b2 |= ambe_d[7] << 4; + b2 |= ambe_d[8] << 3; + b2 |= ambe_d[9] << 2; + b2 |= ambe_d[42] << 1; + b2 |= ambe_d[43]; + + deltaGamma = AmbePlusDg[b2]; + cur_mp->gamma = deltaGamma + ((float)0.5 * prev_mp->gamma); +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: b2: %i, deltaGamma: %f gamma: %f gamma-1: %f", b2, deltaGamma, cur_mp->gamma, prev_mp->gamma); +#endif + + // decode PRBA vectors + Gm[1] = 0; + + // load b3 from ambe_d + b3 = 0; + b3 |= ambe_d[10] << 8; + b3 |= ambe_d[11] << 7; + b3 |= ambe_d[12] << 6; + b3 |= ambe_d[13] << 5; + b3 |= ambe_d[14] << 4; + b3 |= ambe_d[15] << 3; + b3 |= ambe_d[16] << 2; + b3 |= ambe_d[44] << 1; + b3 |= ambe_d[45]; + Gm[2] = AmbePlusPRBA24[b3][0]; + Gm[3] = AmbePlusPRBA24[b3][1]; + Gm[4] = AmbePlusPRBA24[b3][2]; + + // load b4 from ambe_d + b4 = 0; + b4 |= ambe_d[17] << 6; + b4 |= ambe_d[18] << 5; + b4 |= ambe_d[19] << 4; + b4 |= ambe_d[20] << 3; + b4 |= ambe_d[21] << 2; + b4 |= ambe_d[46] << 1; + b4 |= ambe_d[47]; + Gm[5] = AmbePlusPRBA58[b4][0]; + Gm[6] = AmbePlusPRBA58[b4][1]; + Gm[7] = AmbePlusPRBA58[b4][2]; + Gm[8] = AmbePlusPRBA58[b4][3]; + +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: b3: %i Gm[2]: %f Gm[3]: %f Gm[4]: %f b4: %i Gm[5]: %f Gm[6]: %f Gm[7]: %f Gm[8]: %f", b3, Gm[2], Gm[3], Gm[4], b4, Gm[5], Gm[6], Gm[7], Gm[8]); +#endif + + // compute Ri + for (i = 1; i <= 8; i++) { + sum = 0; + for (m = 1; m <= 8; m++) { + if (m == 1) { + am = 1; + } + else { + am = 2; + } + sum = sum + ((float)am * Gm[m] * cosf((M_PI * (float)(m - 1) * ((float)i - (float)0.5)) / (float)8)); + } + Ri[i] = sum; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: R%i: %f ", i, Ri[i]); +#endif + } + + // generate first to elements of each Ci,k block from PRBA vector + rconst = ((float)1 / ((float)2 * M_SQRT2)); + Cik[1][1] = (float)0.5 * (Ri[1] + Ri[2]); + Cik[1][2] = rconst * (Ri[1] - Ri[2]); + Cik[2][1] = (float)0.5 * (Ri[3] + Ri[4]); + Cik[2][2] = rconst * (Ri[3] - Ri[4]); + Cik[3][1] = (float)0.5 * (Ri[5] + Ri[6]); + Cik[3][2] = rconst * (Ri[5] - Ri[6]); + Cik[4][1] = (float)0.5 * (Ri[7] + Ri[8]); + Cik[4][2] = rconst * (Ri[7] - Ri[8]); + + // decode HOC + + // load b5 from ambe_d + b5 = 0; + b5 |= ambe_d[22] << 3; + b5 |= ambe_d[23] << 2; + b5 |= ambe_d[25] << 1; + b5 |= ambe_d[26]; + + // load b6 from ambe_d + b6 = 0; + b6 |= ambe_d[27] << 3; + b6 |= ambe_d[28] << 2; + b6 |= ambe_d[29] << 1; + b6 |= ambe_d[30]; + + // load b7 from ambe_d + b7 = 0; + b7 |= ambe_d[31] << 3; + b7 |= ambe_d[32] << 2; + b7 |= ambe_d[33] << 1; + b7 |= ambe_d[34]; + + // load b8 from ambe_d + b8 = 0; + b8 |= ambe_d[35] << 3; + b8 |= ambe_d[36] << 2; + b8 |= ambe_d[37] << 1; + //b8 |= 0; // least significant bit of hoc3 unused here, and according to the patent is forced to 0 when not used + + // lookup Ji + Ji[1] = AmbePlusLmprbl[L][0]; + Ji[2] = AmbePlusLmprbl[L][1]; + Ji[3] = AmbePlusLmprbl[L][2]; + Ji[4] = AmbePlusLmprbl[L][3]; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: Ji[1]: %i Ji[2]: %i Ji[3]: %i Ji[4]: %i", Ji[1], Ji[2], Ji[3], Ji[4]); + fprintf(stderr, "MBE: AMBE: b5: %i b6: %i b7: %i b8: %i", b5, b6, b7, b8); +#endif + + // Load Ci,k with the values from the HOC tables + // there appear to be a couple typos in eq. 37 so we will just do what makes sense + // (3 <= k <= Ji and k<=6) + for (k = 3; k <= Ji[1]; k++) { + if (k > 6) { + Cik[1][k] = 0; + } + else { + Cik[1][k] = AmbePlusHOCb5[b5][k - 3]; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: C1,%i: %f ", k, Cik[1][k]); +#endif + } + } + + for (k = 3; k <= Ji[2]; k++) { + if (k > 6) { + Cik[2][k] = 0; + } + else { + Cik[2][k] = AmbePlusHOCb6[b6][k - 3]; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: C2,%i: %f ", k, Cik[2][k]); +#endif + } + } + + for (k = 3; k <= Ji[3]; k++) { + if (k > 6) { + Cik[3][k] = 0; + } + else { + Cik[3][k] = AmbePlusHOCb7[b7][k - 3]; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: C3,%i: %f ", k, Cik[3][k]); +#endif + } + } + + for (k = 3; k <= Ji[4]; k++) { + if (k > 6) { + Cik[4][k] = 0; + } + else { + Cik[4][k] = AmbePlusHOCb8[b8][k - 3]; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: C4,%i: %f ", k, Cik[4][k]); +#endif + } + } + + // inverse DCT each Ci,k to give ci,j (Tl) + l = 1; + for (i = 1; i <= 4; i++) { + ji = Ji[i]; + for (j = 1; j <= ji; j++) { + sum = 0; + for (k = 1; k <= ji; k++) { + if (k == 1) { + ak = 1; + } + else { + ak = 2; + } +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: j: %i Cik[%i][%i]: %f ", j, i, k, Cik[i][k]); +#endif + sum = sum + ((float)ak * Cik[i][k] * cosf((M_PI * (float)(k - 1) * ((float)j - (float)0.5)) / (float)ji)); + } + Tl[l] = sum; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: Tl[%i]: %f", l, Tl[l]); +#endif + l++; + } + } + + // determine log2Ml by applying ci,j to previous log2Ml + + // fix for when L > L(-1) + if (cur_mp->L > prev_mp->L) { + for (l = (prev_mp->L) + 1; l <= cur_mp->L; l++) { + prev_mp->Ml[l] = prev_mp->Ml[prev_mp->L]; + prev_mp->log2Ml[l] = prev_mp->log2Ml[prev_mp->L]; + } + } + prev_mp->log2Ml[0] = prev_mp->log2Ml[1]; + prev_mp->Ml[0] = prev_mp->Ml[1]; + + // Part 1 + Sum43 = 0; + for (l = 1; l <= cur_mp->L; l++) { + // eq. 40 + flokl[l] = ((float)prev_mp->L / (float)cur_mp->L) * (float)l; + intkl[l] = (int)(flokl[l]); +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: flok%i: %f, intk%i: %i ", l, flokl[l], l, intkl[l]); +#endif + // eq. 41 + deltal[l] = flokl[l] - (float)intkl[l]; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: delta%i: %f ", l, deltal[l]); +#endif + // eq 43 + Sum43 = Sum43 + ((((float)1 - deltal[l]) * prev_mp->log2Ml[intkl[l]]) + (deltal[l] * prev_mp->log2Ml[intkl[l] + 1])); + } + + Sum43 = (((float)0.65 / (float)cur_mp->L) * Sum43); +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: Sum43: %f", Sum43); +#endif + + // Part 2 + Sum42 = 0; + for (l = 1; l <= cur_mp->L; l++) { + Sum42 += Tl[l]; + } + + Sum42 = Sum42 / (float)cur_mp->L; + BigGamma = cur_mp->gamma - ((float)0.5 * (log((float)cur_mp->L) / log((float)2))) - Sum42; + //BigGamma=cur_mp->gamma - ((float)0.5 * log((float)cur_mp->L)) - Sum42; + + // Part 3 + for (l = 1; l <= cur_mp->L; l++) { + c1 = ((float)0.65 * ((float)1 - deltal[l]) * prev_mp->log2Ml[intkl[l]]); + c2 = ((float)0.65 * deltal[l] * prev_mp->log2Ml[intkl[l] + 1]); + cur_mp->log2Ml[l] = Tl[l] + c1 + c2 - Sum43 + BigGamma; + // inverse log to generate spectral amplitudes + if (cur_mp->Vl[l] == 1) + { + cur_mp->Ml[l] = exp((float)0.693 * cur_mp->log2Ml[l]); + } + else + { + cur_mp->Ml[l] = unvc * exp((float)0.693 * cur_mp->log2Ml[l]); + } +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: flokl[%i]: %f, intkl[%i]: %i", l, flokl[l], l, intkl[l]); + fprintf(stderr, "MBE: AMBE: deltal[%i]: %f", l, deltal[l]); + fprintf(stderr, "MBE: AMBE: prev_mp->log2Ml[%i]: %f", l, prev_mp->log2Ml[intkl[l]]); + fprintf(stderr, "MBE: AMBE: BigGamma: %f c1: %f c2: %f Sum43: %f Tl[%i]: %f log2Ml[%i]: %f Ml[%i]: %f", BigGamma, c1, c2, Sum43, l, Tl[l], l, cur_mp->log2Ml[l], l, cur_mp->Ml[l]); +#endif + } + + return (0); +} + +/* */ + +void mbe_demodulateAmbe3600x2400Data(char ambe_fr[4][24]) +{ + int i, j, k; + unsigned short pr[115]; + unsigned short foo = 0; + + // create pseudo-random modulator + for (i = 23; i >= 12; i--) { + foo <<= 1; + foo |= ambe_fr[0][i]; + } + + pr[0] = (16 * foo); + for (i = 1; i < 24; i++) { + pr[i] = (173 * pr[i - 1]) + 13849 - (65536 * (((173 * pr[i - 1]) + 13849) / 65536)); + } + + for (i = 1; i < 24; i++) { + pr[i] = pr[i] / 32768; + } + + // demodulate ambe_fr with pr + k = 1; + for (j = 22; j >= 0; j--) { + ambe_fr[1][j] = ((ambe_fr[1][j]) ^ pr[k]); + k++; + } +} + +/* */ + +void mbe_processAmbe2400DataF(float* aout_buf, int* errs, int* errs2, char* err_str, char ambe_d[49], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality) +{ + int i, bad; + + for (i = 0; i < *errs2; i++) { + *err_str = '='; + err_str++; + } + + bad = mbe_decodeAmbe2400Parms(ambe_d, cur_mp, prev_mp); + if (bad == 2) { + // Erasure frame + *err_str = 'E'; + err_str++; + cur_mp->repeat = 0; + } + else if (bad == 3) { + // Tone Frame + *err_str = 'T'; + err_str++; + cur_mp->repeat = 0; + } + else if (*errs2 > 3) { + mbe_useLastMbeParms(cur_mp, prev_mp); + cur_mp->repeat++; + *err_str = 'R'; + err_str++; + } + else { + cur_mp->repeat = 0; + } + + if (bad == 0) { + if (cur_mp->repeat <= 3) { + mbe_moveMbeParms(cur_mp, prev_mp); + mbe_spectralAmpEnhance(cur_mp); + mbe_synthesizeSpeechF(aout_buf, cur_mp, prev_mp_enhanced, uvquality); + mbe_moveMbeParms(cur_mp, prev_mp_enhanced); + } + else { + *err_str = 'M'; + err_str++; + mbe_synthesizeSilenceF(aout_buf); + mbe_initMbeParms(cur_mp, prev_mp, prev_mp_enhanced); + } + } + else { + mbe_synthesizeSilenceF(aout_buf); + mbe_initMbeParms(cur_mp, prev_mp, prev_mp_enhanced); + } + + *err_str = 0; +} + +/* */ + +void mbe_processAmbe2400Data(short* aout_buf, int* errs, int* errs2, char* err_str, char ambe_d[49], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality) +{ + float float_buf[160]; + mbe_processAmbe2400DataF(float_buf, errs, errs2, err_str, ambe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality); + mbe_floatToShort(float_buf, aout_buf); +} + +/* */ + +void mbe_processAmbe3600x2400FrameF(float* aout_buf, int* errs, int* errs2, char* err_str, char ambe_fr[4][24], char ambe_d[49], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality) +{ + *errs = 0; + *errs2 = 0; + *errs = mbe_eccAmbe3600x2400C0(ambe_fr); + mbe_demodulateAmbe3600x2400Data(ambe_fr); + + *errs2 = *errs; + *errs2 += mbe_eccAmbe3600x2400Data(ambe_fr, ambe_d); + + mbe_processAmbe2400DataF(aout_buf, errs, errs2, err_str, ambe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality); +} + +/* */ + +void mbe_processAmbe3600x2400Frame(short* aout_buf, int* errs, int* errs2, char* err_str, char ambe_fr[4][24], char ambe_d[49], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality) +{ + float float_buf[160]; + mbe_processAmbe3600x2400FrameF(float_buf, errs, errs2, err_str, ambe_fr, ambe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality); + mbe_floatToShort(float_buf, aout_buf); +} diff --git a/vocoder/ambe3600x2400_const.h b/vocoder/ambe3600x2400_const.h new file mode 100644 index 0000000..0bb9b26 --- /dev/null +++ b/vocoder/ambe3600x2400_const.h @@ -0,0 +1,903 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - MBE Vocoder + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + */ +/** + * @file ambe3600x2400_const.h + * @ingroup vocoder + */ + +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#if !defined(__AMBE3600x2400_CONST_H__) +#define __AMBE3600x2400_CONST_H__ + +#ifdef _MSC_VER +#pragma warning(disable: 4305) +#endif + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +const float AmbePlusLtable[126] = { + 9, 9, 9, 9, 9, 9, + 10, 10, 10, 10, 10, 10, + 11, 11, 11, 11, 11, 11, + 12, 12, 12, 12, 12, 13, + 13, 13, 13, 13, 14, 14, + 14, 14, 15, 15, 15, 15, + 16, 16, 16, 16, 17, 17, + 17, 17, 18, 18, 18, 18, + 19, 19, 19, 20, 20, 20, + 21, 21, 21, 22, 22, 22, + 23, 23, 23, 24, 24, 24, + 25, 25, 26, 26, 26, 27, + 27, 28, 28, 29, 29, 30, + 30, 30, 31, 31, 32, 32, + 33, 33, 34, 34, 35, 36, + 36, 37, 37, 38, 38, 39, + 40, 40, 41, 42, 42, 43, + 43, 44, 45, 46, 46, 47, + 48, 48, 49, 50, 51, 52, + 52, 53, 54, 55, 56, 56, + 56, 56, 56, 56, 56, 56 // last line is padded +}; + +/* + * V/UV Quantization Vectors + */ +const int AmbePlusVuv[16][8] = { + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 1, 1}, + {0, 0, 0, 0, 1, 1, 0, 0}, + {0, 0, 0, 0, 1, 1, 1, 1}, + {0, 0, 1, 1, 0, 0, 0, 0}, + {0, 0, 1, 1, 0, 0, 1, 1}, + {0, 0, 1, 1, 1, 1, 0, 0}, + {0, 0, 1, 1, 1, 1, 1, 1}, + {1, 1, 0, 0, 0, 0, 0, 0}, + {1, 1, 0, 0, 0, 0, 1, 1}, + {1, 1, 0, 0, 1, 1, 0, 0}, + {1, 1, 0, 0, 1, 1, 1, 1}, + {1, 1, 1, 1, 0, 0, 0, 0}, + {1, 1, 1, 1, 0, 0, 1, 1}, + {1, 1, 1, 1, 1, 1, 0, 0}, + {1, 1, 1, 1, 1, 1, 1, 1} +}; + +/* + * Log Magnitude Prediction Residual Block Lengths + */ +const int AmbePlusLmprbl[57][4] = { + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {2, 2, 2, 3,}, + {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} +}; + +/* + * Gain Quantizer Levels + */ +const float AmbePlusDg[64] = { + 0.000000, 0.118200, 0.215088, 0.421167, 0.590088, 0.749075, 0.879395, 0.996388, + 1.092285, 1.171577, 1.236572, 1.313450, 1.376465, 1.453342, 1.516357, 1.600346, + 1.669189, 1.742847, 1.803223, 1.880234, 1.943359, 2.025067, 2.092041, 2.178042, + 2.248535, 2.331718, 2.399902, 2.492343, 2.568115, 2.658677, 2.732910, 2.816496, + 2.885010, 2.956386, 3.014893, 3.078890, 3.131348, 3.206615, 3.268311, 3.344785, + 3.407471, 3.484885, 3.548340, 3.623339, 3.684814, 3.764509, 3.829834, 3.915298, + 3.985352, 4.072560, 4.144043, 4.231251, 4.302734, 4.399066, 4.478027, 4.572883, + 4.650635, 4.760785, 4.851074, 4.972361, 5.071777, 5.226203, 5.352783, 5.352783 +}; + +/* + * PRBA24 Vector Quantizer Levels + */ +const float AmbePlusPRBA24[512][3] = { + {-1.250000, -0.312500, -0.625000}, + {-0.750000, -0.437500, -0.437500}, + {-0.437500, -0.375000, -0.312500}, + {-0.437500, -0.625000, -0.500000}, + {-1.000000, -0.187500, -0.187500}, + {-0.625000, -0.625000, -0.125000}, + {-0.500000, -0.187500, -0.187500}, + {-0.375000, -0.437500, -0.187500}, + {-1.062500, -0.750000, -0.125000}, + {-0.625000, -0.312500, -0.062500}, + {-0.500000, -1.000000, -0.062500}, + {-0.375000, -0.312500, -0.062500}, + {-0.687500, -0.250000, 0.187500}, + {-0.437500, -0.500000, 0.375000}, + {-0.375000, -0.375000, 0.062500}, + {-0.312500, -0.187500, 0.000000}, + {-0.625000, -0.187500, -0.187500}, + {-0.500000, -0.062500, -0.250000}, + {-0.500000, -0.125000, -0.437500}, + {-0.312500, -0.062500, -0.312500}, + {-0.562500, -0.187500, -0.062500}, + {-0.375000, -0.187500, -0.062500}, + {-0.375000, -0.125000, -0.187500}, + {-0.312500, -0.187500, -0.125000}, + {-0.562500, 0.000000, 0.125000}, + {-0.437500, 0.000000, 0.062500}, + {-0.312500, -0.125000, 0.125000}, + {-0.312500, -0.062500, 0.000000}, + {-0.937500, -0.062500, 0.125000}, + {-0.750000, -0.125000, 0.375000}, + {-0.437500, -0.062500, 0.250000}, + {-0.375000, -0.062500, 0.625000}, + {-0.875000, 0.062500, -0.312500}, + {-0.500000, 0.125000, -0.375000}, + {-0.312500, 0.062500, -0.250000}, + {-0.312500, 0.000000, -0.312500}, + {-0.687500, 0.125000, -0.187500}, + {-0.437500, 0.062500, -0.062500}, + {-0.375000, 0.125000, -0.125000}, + {-0.312500, 0.062500, -0.125000}, + {-0.687500, 0.062500, -0.062500}, + {-0.437500, 0.187500, 0.062500}, + {-0.312500, 0.062500, 0.000000}, + {-0.250000, 0.000000, 0.125000}, + {-1.312500, 0.062500, 0.312500}, + {-0.562500, 0.125000, 0.250000}, + {-0.375000, 0.062500, 0.375000}, + {-0.312500, 0.125000, 0.125000}, + {-1.250000, 0.187500, -0.250000}, + {-0.687500, 0.437500, -0.375000}, + {-0.562500, 0.250000, -0.250000}, + {-0.312500, 0.375000, -0.562500}, + {-0.812500, 0.437500, -0.062500}, + {-0.625000, 0.187500, -0.062500}, + {-0.500000, 0.375000, -0.062500}, + {-0.375000, 0.375000, -0.250000}, + {-0.812500, 0.187500, 0.187500}, + {-0.562500, 0.625000, 0.062500}, + {-0.500000, 0.312500, 0.125000}, + {-0.312500, 0.312500, 0.062500}, + {-0.500000, 0.250000, 0.625000}, + {-0.375000, 0.250000, 0.312500}, + {-0.312500, 0.500000, 0.500000}, + {-0.312500, 0.500000, 0.250000}, + {-0.250000, -0.437500, -0.375000}, + {-0.250000, -0.250000, -0.312500}, + {-0.250000, -0.687500, -0.312500}, + {-0.125000, -0.500000, -0.250000}, + {-0.250000, -0.375000, -0.125000}, + {-0.125000, -0.312500, -0.187500}, + {-0.125000, -0.250000, -0.250000}, + {-0.062500, -0.187500, -0.125000}, + {-0.187500, -0.187500, -0.062500}, + {-0.187500, -0.500000, 0.000000}, + {-0.125000, -0.375000, -0.062500}, + {-0.062500, -0.250000, 0.000000}, + {-0.250000, -0.312500, 0.250000}, + {-0.187500, -0.250000, 0.125000}, + {-0.187500, -0.250000, 0.000000}, + {-0.125000, -0.625000, 0.187500}, + {-0.187500, -0.062500, -0.250000}, + {-0.125000, -0.062500, -0.187500}, + {-0.062500, 0.000000, -0.312500}, + {-0.062500, 0.000000, -0.812500}, + {-0.250000, -0.125000, -0.062500}, + {-0.250000, -0.062500, -0.125000}, + {-0.187500, 0.000000, -0.062500}, + {-0.125000, -0.062500, -0.062500}, + {-0.187500, 0.000000, 0.125000}, + {-0.187500, -0.062500, 0.062500}, + {-0.125000, -0.125000, 0.125000}, + {-0.125000, -0.187500, 0.062500}, + {-0.187500, -0.062500, 0.437500}, + {-0.187500, -0.125000, 0.187500}, + {-0.125000, 0.000000, 0.187500}, + {-0.062500, 0.000000, 0.375000}, + {-0.187500, 0.000000, -0.187500}, + {-0.187500, 0.125000, -0.125000}, + {-0.187500, 0.125000, -0.187500}, + {-0.125000, 0.125000, -0.375000}, + {-0.250000, 0.187500, 0.000000}, + {-0.125000, 0.000000, -0.125000}, + {-0.062500, 0.000000, -0.062500}, + {-0.062500, 0.125000, -0.062500}, + {-0.187500, 0.125000, 0.125000}, + {-0.187500, 0.062500, 0.000000}, + {-0.125000, 0.125000, 0.062500}, + {-0.062500, 0.000000, 0.000000}, + {-0.250000, 0.062500, 0.250000}, + {-0.125000, 0.125000, 0.312500}, + {-0.125000, 0.125000, 0.125000}, + {-0.062500, 0.000000, 0.125000}, + {-0.250000, 0.250000, -0.187500}, + {-0.187500, 0.687500, -0.187500}, + {-0.125000, 0.250000, -0.125000}, + {-0.062500, 0.375000, -0.312500}, + {-0.187500, 0.187500, -0.062500}, + {-0.187500, 0.437500, -0.062500}, + {-0.125000, 0.375000, 0.062500}, + {-0.062500, 0.500000, 0.000000}, + {-0.250000, 0.250000, 0.187500}, + {-0.125000, 0.562500, 0.250000}, + {-0.125000, 0.437500, 0.125000}, + {-0.062500, 0.312500, 0.125000}, + {-0.250000, 0.187500, 0.437500}, + {-0.187500, 0.250000, 0.312500}, + {-0.062500, 0.312500, 0.250000}, + {-0.062500, 0.437500, 0.562500}, + {-0.062500, -0.375000, -0.250000}, + {0.000000, -0.250000, -0.375000}, + {0.062500, -0.250000, -0.312500}, + {0.062500, -0.375000, -0.312500}, + {0.000000, -0.312500, -0.125000}, + {0.000000, -0.250000, -0.062500}, + {0.062500, -0.500000, -0.125000}, + {0.062500, -0.250000, -0.187500}, + {0.000000, -0.437500, 0.000000}, + {0.000000, -0.250000, 0.000000}, + {0.000000, -0.187500, 0.062500}, + {0.062500, -0.375000, 0.000000}, + {-0.062500, -0.187500, 0.125000}, + {-0.062500, -0.375000, 0.062500}, + {0.000000, -0.250000, 0.187500}, + {0.000000, -0.312500, 0.125000}, + {-0.062500, -0.125000, -0.250000}, + {0.000000, -0.125000, -0.500000}, + {0.000000, -0.062500, -0.250000}, + {0.062500, -0.187500, -0.187500}, + {-0.062500, -0.125000, -0.062500}, + {-0.062500, -0.187500, 0.000000}, + {0.000000, -0.125000, -0.125000}, + {0.000000, -0.187500, -0.125000}, + {-0.062500, -0.062500, 0.125000}, + {0.000000, -0.125000, 0.000000}, + {0.062500, -0.062500, 0.000000}, + {0.062500, -0.125000, 0.000000}, + {-0.062500, -0.125000, 0.437500}, + {0.000000, -0.062500, 0.250000}, + {0.000000, -0.125000, 0.187500}, + {0.062500, -0.187500, 0.312500}, + {-0.062500, 0.062500, -0.187500}, + {-0.062500, 0.000000, -0.125000}, + {0.062500, 0.062500, -0.125000}, + {0.062500, 0.062500, -0.312500}, + {0.000000, 0.062500, -0.062500}, + {0.000000, 0.000000, 0.000000}, + {0.062500, 0.000000, -0.125000}, + {0.062500, 0.125000, -0.125000}, + {0.000000, 0.062500, 0.125000}, + {0.000000, 0.125000, 0.062500}, + {0.062500, 0.000000, 0.125000}, + {0.062500, 0.062500, 0.000000}, + {-0.062500, 0.062500, 0.187500}, + {-0.062500, 0.062500, 0.437500}, + {0.000000, 0.062500, 0.250000}, + {0.062500, 0.125000, 0.187500}, + {0.000000, 0.250000, -0.250000}, + {0.000000, 0.375000, -0.062500}, + {0.000000, 0.187500, -0.125000}, + {0.062500, 0.500000, -0.187500}, + {0.000000, 0.250000, 0.000000}, + {0.000000, 0.187500, 0.062500}, + {0.062500, 0.312500, 0.062500}, + {0.062500, 0.187500, 0.000000}, + {-0.062500, 0.187500, 0.187500}, + {0.000000, 0.250000, 0.125000}, + {0.062500, 0.375000, 0.187500}, + {0.062500, 0.250000, 0.250000}, + {-0.062500, 0.187500, 0.500000}, + {0.000000, 0.312500, 0.375000}, + {0.000000, 0.125000, 0.312500}, + {0.062500, 0.187500, 0.250000}, + {0.125000, -0.125000, -0.312500}, + {0.125000, -0.312500, -0.187500}, + {0.187500, -0.375000, -0.250000}, + {0.187500, -0.187500, -0.125000}, + {0.125000, -0.187500, -0.062500}, + {0.125000, -0.687500, -0.062500}, + {0.125000, -0.187500, -0.062500}, + {0.187500, -0.375000, -0.062500}, + {0.062500, -0.250000, 0.062500}, + {0.125000, -0.187500, 0.000000}, + {0.125000, -0.187500, 0.125000}, + {0.187500, -0.250000, 0.125000}, + {0.062500, -0.187500, 0.187500}, + {0.125000, -0.312500, 0.250000}, + {0.125000, -0.375000, 0.125000}, + {0.187500, -0.187500, 0.187500}, + {0.062500, -0.125000, -0.125000}, + {0.062500, 0.000000, -0.187500}, + {0.125000, -0.062500, -0.187500}, + {0.125000, -0.125000, -0.062500}, + {0.062500, -0.062500, 0.062500}, + {0.125000, -0.062500, 0.000000}, + {0.125000, -0.125000, 0.000000}, + {0.187500, -0.062500, 0.000000}, + {0.062500, 0.000000, 0.187500}, + {0.125000, -0.125000, 0.125000}, + {0.125000, -0.062500, 0.125000}, + {0.187500, -0.125000, 0.125000}, + {0.062500, -0.062500, 0.250000}, + {0.062500, 0.000000, 0.437500}, + {0.187500, -0.125000, 0.375000}, + {0.187500, -0.125000, 0.250000}, + {0.062500, 0.125000, -0.500000}, + {0.125000, 0.125000, -0.125000}, + {0.125000, 0.000000, -0.125000}, + {0.187500, 0.000000, -0.312500}, + {0.062500, 0.062500, 0.062500}, + {0.062500, 0.125000, 0.000000}, + {0.187500, 0.062500, -0.062500}, + {0.187500, 0.125000, 0.062500}, + {0.125000, 0.125000, 0.125000}, + {0.125000, 0.000000, 0.125000}, + {0.187500, 0.000000, 0.062500}, + {0.187500, 0.125000, 0.125000}, + {0.062500, 0.125000, 0.375000}, + {0.125000, 0.062500, 0.687500}, + {0.125000, 0.062500, 0.187500}, + {0.125000, 0.000000, 0.250000}, + {0.062500, 0.187500, -0.125000}, + {0.125000, 0.187500, -0.250000}, + {0.187500, 0.312500, -0.312500}, + {0.187500, 0.250000, -0.125000}, + {0.062500, 0.437500, 0.000000}, + {0.125000, 0.250000, 0.000000}, + {0.187500, 0.187500, 0.062500}, + {0.187500, 0.187500, -0.062500}, + {0.062500, 0.187500, 0.187500}, + {0.125000, 0.375000, 0.062500}, + {0.187500, 0.250000, 0.125000}, + {0.187500, 0.250000, 0.187500}, + {0.125000, 0.312500, 0.375000}, + {0.187500, 0.687500, 0.312500}, + {0.187500, 0.187500, 0.250000}, + {0.187500, 0.312500, 0.250000}, + {0.187500, -0.562500, -0.250000}, + {0.187500, -0.937500, -0.687500}, + {0.312500, -0.312500, -0.375000}, + {0.312500, -0.500000, -0.625000}, + {0.187500, -0.312500, 0.000000}, + {0.187500, -0.250000, -0.250000}, + {0.250000, -0.312500, -0.125000}, + {0.312500, -0.187500, 0.000000}, + {0.187500, -0.437500, 0.062500}, + {0.250000, -0.250000, 0.000000}, + {0.250000, -0.312500, 0.125000}, + {0.250000, -1.000000, 0.125000}, + {0.187500, -0.312500, 0.437500}, + {0.187500, -0.625000, 0.187500}, + {0.187500, -0.250000, 0.187500}, + {0.312500, -0.312500, 0.250000}, + {0.187500, -0.062500, -0.187500}, + {0.187500, -0.125000, -0.437500}, + {0.250000, -0.187500, -0.125000}, + {0.250000, -0.125000, -0.250000}, + {0.250000, -0.187500, -0.062500}, + {0.250000, -0.062500, -0.062500}, + {0.250000, -0.062500, -0.125000}, + {0.312500, -0.125000, -0.062500}, + {0.187500, -0.187500, 0.062500}, + {0.250000, -0.062500, 0.000000}, + {0.250000, -0.125000, 0.000000}, + {0.250000, -0.125000, 0.125000}, + {0.250000, -0.062500, 0.312500}, + {0.250000, -0.187500, 0.312500}, + {0.250000, -0.062500, 0.250000}, + {0.312500, -0.187500, 0.187500}, + {0.187500, 0.125000, -0.187500}, + {0.187500, 0.062500, -0.125000}, + {0.312500, 0.062500, -0.312500}, + {0.312500, 0.062500, -0.187500}, + {0.250000, -0.062500, 0.062500}, + {0.250000, 0.000000, -0.062500}, + {0.250000, 0.062500, 0.000000}, + {0.312500, 0.000000, 0.000000}, + {0.187500, 0.000000, 0.187500}, + {0.187500, 0.062500, 0.125000}, + {0.312500, 0.000000, 0.125000}, + {0.312500, 0.062500, 0.187500}, + {0.187500, 0.062500, 0.187500}, + {0.250000, 0.062500, 0.312500}, + {0.250000, 0.000000, 0.250000}, + {0.250000, 0.062500, 0.437500}, + {0.250000, 0.250000, -0.187500}, + {0.250000, 0.250000, -0.062500}, + {0.250000, 0.125000, -0.062500}, + {0.312500, 0.625000, -0.062500}, + {0.187500, 0.312500, 0.062500}, + {0.250000, 0.375000, -0.062500}, + {0.250000, 0.125000, 0.062500}, + {0.312500, 0.187500, -0.062500}, + {0.250000, 0.437500, 0.125000}, + {0.250000, 0.187500, 0.187500}, + {0.250000, 0.187500, 0.062500}, + {0.312500, 0.250000, 0.187500}, + {0.187500, 0.187500, 0.375000}, + {0.250000, 0.187500, 0.250000}, + {0.250000, 0.312500, 0.437500}, + {0.250000, 0.375000, 0.625000}, + {0.312500, -0.250000, -0.125000}, + {0.312500, -0.312500, -0.187500}, + {0.312500, -0.187500, -0.062500}, + {0.437500, -0.625000, -0.250000}, + {0.312500, -0.312500, 0.062500}, + {0.312500, -0.312500, 0.000000}, + {0.312500, -0.375000, -0.062500}, + {0.375000, -0.250000, 0.062500}, + {0.312500, -0.437500, 0.187500}, + {0.312500, -0.187500, 0.062500}, + {0.312500, -0.312500, 0.125000}, + {0.375000, -0.250000, 0.125000}, + {0.375000, -0.375000, 0.375000}, + {0.375000, -0.250000, 0.437500}, + {0.375000, -0.250000, 0.250000}, + {0.375000, -0.312500, 0.625000}, + {0.375000, -0.125000, -0.062500}, + {0.375000, -0.125000, -0.125000}, + {0.375000, -0.062500, -0.125000}, + {0.437500, 0.000000, -0.312500}, + {0.312500, -0.125000, 0.062500}, + {0.312500, 0.000000, 0.000000}, + {0.375000, -0.062500, 0.000000}, + {0.375000, -0.187500, 0.000000}, + {0.312500, -0.062500, 0.062500}, + {0.375000, -0.062500, 0.187500}, + {0.375000, -0.125000, 0.125000}, + {0.437500, -0.062500, 0.062500}, + {0.312500, -0.125000, 0.312500}, + {0.375000, -0.062500, 0.562500}, + {0.375000, -0.187500, 0.250000}, + {0.437500, -0.062500, 0.187500}, + {0.312500, 0.000000, -0.187500}, + {0.312500, 0.000000, -0.062500}, + {0.375000, 0.062500, -0.187500}, + {0.375000, 0.125000, -0.250000}, + {0.312500, 0.062500, -0.062500}, + {0.375000, 0.062500, 0.000000}, + {0.375000, 0.125000, 0.000000}, + {0.437500, 0.000000, 0.000000}, + {0.312500, 0.062500, 0.062500}, + {0.312500, 0.125000, 0.125000}, + {0.375000, 0.000000, 0.062500}, + {0.437500, 0.125000, 0.062500}, + {0.312500, 0.062500, 0.250000}, + {0.375000, 0.000000, 0.312500}, + {0.375000, 0.000000, 0.187500}, + {0.375000, 0.125000, 0.187500}, + {0.312500, 0.187500, -0.437500}, + {0.312500, 0.187500, -0.250000}, + {0.437500, 0.500000, -0.375000}, + {0.437500, 0.250000, -0.187500}, + {0.312500, 0.250000, -0.125000}, + {0.312500, 0.187500, 0.062500}, + {0.312500, 0.312500, 0.000000}, + {0.375000, 0.125000, -0.125000}, + {0.312500, 0.250000, 0.062500}, + {0.375000, 0.312500, 0.125000}, + {0.375000, 0.187500, 0.125000}, + {0.437500, 0.312500, 0.250000}, + {0.312500, 0.437500, 0.312500}, + {0.375000, 0.125000, 0.375000}, + {0.375000, 0.750000, 0.687500}, + {0.437500, 0.125000, 0.625000}, + {0.437500, -0.250000, -0.312500}, + {0.437500, -0.250000, -0.187500}, + {0.500000, -0.375000, -0.312500}, + {0.562500, -0.250000, -0.125000}, + {0.437500, -0.250000, 0.000000}, + {0.500000, -0.500000, -0.062500}, + {0.500000, -0.312500, -0.125000}, + {0.562500, -0.375000, 0.000000}, + {0.437500, -0.312500, 0.187500}, + {0.437500, -0.375000, 0.125000}, + {0.500000, -0.187500, 0.062500}, + {0.625000, -0.250000, 0.187500}, + {0.437500, -0.375000, 0.312500}, + {0.500000, -0.250000, 0.375000}, + {0.562500, -0.562500, 0.312500}, + {0.625000, -0.437500, 0.187500}, + {0.437500, -0.187500, -0.250000}, + {0.437500, -0.187500, -0.062500}, + {0.437500, -0.062500, -0.125000}, + {0.625000, -0.187500, -0.125000}, + {0.437500, -0.125000, 0.000000}, + {0.500000, -0.125000, -0.062500}, + {0.562500, -0.125000, 0.000000}, + {0.562500, -0.062500, -0.062500}, + {0.437500, -0.062500, 0.125000}, + {0.500000, -0.187500, 0.125000}, + {0.562500, -0.062500, 0.125000}, + {0.625000, -0.187500, 0.187500}, + {0.437500, -0.062500, 0.375000}, + {0.500000, -0.125000, 0.187500}, + {0.562500, -0.125000, 0.562500}, + {0.562500, -0.125000, 0.250000}, + {0.437500, 0.062500, -0.187500}, + {0.500000, 0.125000, -0.187500}, + {0.562500, 0.000000, -0.187500}, + {0.625000, 0.000000, -0.312500}, + {0.437500, 0.062500, -0.062500}, + {0.500000, 0.062500, 0.000000}, + {0.500000, 0.125000, -0.062500}, + {0.500000, -0.062500, 0.000000}, + {0.437500, 0.062500, 0.187500}, + {0.500000, 0.000000, 0.125000}, + {0.500000, 0.062500, 0.125000}, + {0.562500, 0.125000, 0.000000}, + {0.437500, 0.062500, 0.500000}, + {0.500000, -0.062500, 0.312500}, + {0.562500, 0.000000, 0.250000}, + {0.562500, 0.062500, 0.375000}, + {0.437500, 0.312500, -0.125000}, + {0.437500, 0.187500, -0.125000}, + {0.562500, 0.500000, -0.125000}, + {0.562500, 0.312500, -0.125000}, + {0.437500, 0.250000, -0.062500}, + {0.437500, 0.250000, 0.062500}, + {0.500000, 0.250000, -0.062500}, + {0.625000, 0.125000, -0.125000}, + {0.500000, 0.375000, 0.062500}, + {0.500000, 0.125000, 0.125000}, + {0.500000, 0.562500, 0.125000}, + {0.562500, 0.187500, 0.125000}, + {0.500000, 0.187500, 0.250000}, + {0.500000, 0.625000, 0.375000}, + {0.500000, 0.250000, 0.187500}, + {0.562500, 0.312500, 0.375000}, + {0.625000, -0.312500, -0.187500}, + {0.625000, -0.187500, -0.312500}, + {0.812500, -0.437500, -0.437500}, + {1.375000, -0.187500, -0.375000}, + {0.687500, -0.312500, -0.062500}, + {0.875000, -0.250000, -0.062500}, + {1.062500, -0.187500, 0.062500}, + {1.062500, -0.437500, -0.062500}, + {0.625000, -0.250000, 0.125000}, + {0.750000, -0.125000, 0.062500}, + {0.812500, -0.312500, 0.125000}, + {1.187500, -0.125000, 0.312500}, + {0.625000, -0.312500, 0.562500}, + {0.812500, -0.250000, 0.312500}, + {0.875000, -0.500000, 0.312500}, + {1.000000, -0.312500, 0.500000}, + {0.625000, -0.062500, -0.187500}, + {0.687500, 0.062500, -0.187500}, + {0.812500, -0.062500, -0.187500}, + {1.062500, -0.125000, -0.187500}, + {0.625000, 0.062500, -0.062500}, + {0.687500, -0.125000, -0.062500}, + {0.875000, -0.125000, 0.000000}, + {1.437500, 0.000000, 0.000000}, + {0.625000, 0.000000, 0.062500}, + {0.687500, -0.062500, 0.187500}, + {0.750000, 0.062500, 0.000000}, + {0.812500, 0.000000, 0.125000}, + {0.625000, 0.062500, 0.250000}, + {0.687500, -0.062500, 0.375000}, + {0.687500, 0.000000, 0.500000}, + {0.937500, -0.062500, 0.250000}, + {0.687500, 0.187500, -0.312500}, + {0.750000, 0.187500, -0.500000}, + {1.000000, 0.187500, -0.312500}, + {1.750000, 0.125000, -0.250000}, + {0.750000, 0.187500, -0.125000}, + {0.875000, 0.187500, -0.062500}, + {0.937500, 0.125000, 0.000000}, + {1.187500, 0.187500, -0.187500}, + {0.625000, 0.187500, 0.250000}, + {0.625000, 0.187500, 0.125000}, + {0.687500, 0.187500, 0.000000}, + {0.937500, 0.250000, 0.250000}, + {0.687500, 0.187500, 0.437500}, + {0.750000, 0.062500, 0.312500}, + {0.937500, 0.125000, 0.437500}, + {1.437500, 0.187500, 0.437500}, + {0.625000, 0.250000, -0.062500}, + {0.687500, 0.375000, 0.000000}, + {1.062500, 0.937500, -0.250000}, + {1.375000, 0.375000, -0.250000}, + {0.812500, 0.312500, 0.125000}, + {0.875000, 0.500000, 0.000000}, + {1.062500, 0.375000, 0.062500}, + {1.500000, 0.437500, 0.125000}, + {0.625000, 0.375000, 0.250000}, + {0.875000, 0.375000, 0.312500}, + {1.125000, 0.625000, 0.187500}, + {1.187500, 0.250000, 0.187500}, + {0.687500, 0.437500, 0.437500}, + {0.750000, 0.375000, 0.687500}, + {0.937500, 0.750000, 0.500000}, + {1.312500, 0.687500, 0.625000} +}; + +/* + * PRBA58 Vector Quantizer Levels + */ +const float AmbePlusPRBA58[128][4] = { + {-0.460938, -0.265625, -0.281250, -0.062500}, + {-0.367188, -0.117188, -0.078125, -0.054688}, + {-0.250000, -0.312500, -0.164063, -0.101563}, + {-0.156250, -0.078125, -0.085938, -0.203125}, + {-0.468750, -0.085938, -0.171875, 0.164063}, + {-0.210938, -0.039063, -0.117188, 0.085938}, + {-0.187500, -0.156250, -0.289063, 0.070313}, + {-0.179688, -0.117188, -0.148438, -0.046875}, + {-0.320313, -0.031250, 0.140625, -0.132813}, + {-0.289063, -0.140625, 0.179688, 0.015625}, + {-0.179688, -0.226563, -0.007813, -0.101563}, + {-0.156250, -0.031250, 0.015625, -0.093750}, + {-0.390625, -0.273438, 0.046875, 0.031250}, + {-0.195313, -0.203125, -0.070313, 0.039063}, + {-0.171875, -0.156250, -0.039063, 0.171875}, + {-0.156250, -0.085938, 0.085938, 0.125000}, + {-0.304688, 0.054688, -0.210938, -0.085938}, + {-0.265625, 0.140625, -0.031250, -0.132813}, + {-0.242188, 0.078125, -0.031250, 0.015625}, + {-0.203125, 0.000000, -0.085938, -0.070313}, + {-0.453125, 0.171875, -0.062500, 0.031250}, + {-0.289063, 0.125000, -0.156250, 0.093750}, + {-0.179688, 0.257813, -0.054688, 0.273438}, + {-0.171875, 0.226563, -0.109375, 0.015625}, + {-0.312500, -0.007813, 0.000000, 0.085938}, + {-0.265625, 0.265625, 0.046875, 0.101563}, + {-0.234375, 0.109375, 0.125000, -0.046875}, + {-0.171875, -0.015625, 0.093750, 0.007813}, + {-0.414063, 0.046875, 0.101563, 0.203125}, + {-0.179688, 0.093750, 0.210938, 0.125000}, + {-0.179688, -0.007813, 0.007813, 0.273438}, + {-0.171875, 0.085938, 0.007813, 0.132813}, + {-0.062500, -0.117188, -0.257813, -0.156250}, + {-0.054688, -0.226563, -0.109375, -0.015625}, + {-0.046875, -0.164063, -0.070313, -0.117188}, + {-0.039063, -0.031250, -0.093750, -0.085938}, + {-0.156250, -0.031250, -0.015625, 0.039063}, + {-0.085938, 0.015625, -0.179688, 0.164063}, + {-0.078125, -0.078125, -0.070313, 0.046875}, + {-0.046875, -0.195313, -0.062500, 0.109375}, + {-0.093750, -0.046875, 0.109375, -0.101563}, + {-0.054688, -0.007813, 0.007813, -0.007813}, + {-0.039063, -0.132813, 0.031250, -0.031250}, + {-0.023438, -0.148438, 0.195313, -0.085938}, + {-0.148438, -0.109375, 0.023438, 0.000000}, + {-0.039063, -0.085938, 0.031250, 0.085938}, + {-0.039063, -0.226563, 0.117188, 0.070313}, + {-0.015625, -0.015625, 0.156250, 0.156250}, + {-0.109375, 0.132813, -0.109375, -0.140625}, + {-0.093750, 0.023438, -0.187500, -0.007813}, + {-0.093750, 0.382813, -0.062500, -0.101563}, + {-0.023438, 0.101563, -0.062500, -0.007813}, + {-0.140625, 0.195313, -0.273438, 0.132813}, + {-0.109375, 0.125000, -0.117188, 0.062500}, + {-0.085938, 0.015625, -0.078125, 0.031250}, + {-0.031250, 0.203125, -0.023438, 0.125000}, + {-0.125000, 0.156250, 0.078125, -0.140625}, + {-0.117188, 0.085938, 0.312500, -0.101563}, + {-0.093750, 0.062500, 0.007813, -0.078125}, + {-0.046875, 0.046875, 0.148438, -0.023438}, + {-0.125000, 0.148438, 0.007813, 0.015625}, + {-0.085938, 0.046875, 0.054688, 0.039063}, + {-0.054688, 0.140625, 0.117188, 0.101563}, + {-0.054688, 0.039063, -0.015625, 0.109375}, + {0.046875, -0.062500, -0.054688, -0.226563}, + {0.062500, -0.132813, -0.093750, -0.101563}, + {0.078125, -0.015625, -0.132813, -0.023438}, + {0.085938, -0.421875, -0.140625, -0.062500}, + {-0.007813, -0.054688, -0.054688, 0.179688}, + {0.015625, -0.078125, -0.203125, 0.054688}, + {0.015625, -0.093750, -0.078125, 0.023438}, + {0.062500, -0.179688, -0.187500, 0.148438}, + {0.007813, -0.039063, 0.046875, -0.093750}, + {0.023438, 0.031250, 0.117188, -0.179688}, + {0.101563, -0.171875, 0.093750, -0.171875}, + {0.101563, -0.023438, -0.023438, -0.125000}, + {-0.007813, -0.039063, 0.109375, 0.023438}, + {0.046875, -0.015625, 0.015625, 0.078125}, + {0.054688, -0.046875, -0.023438, -0.023438}, + {0.070313, -0.140625, 0.062500, -0.015625}, + {0.007813, 0.070313, -0.031250, -0.210938}, + {0.015625, 0.140625, -0.179688, -0.046875}, + {0.023438, 0.039063, -0.039063, -0.039063}, + {0.054688, 0.117188, -0.007813, -0.101563}, + {0.015625, 0.046875, -0.117188, 0.078125}, + {0.054688, 0.054688, -0.281250, 0.164063}, + {0.062500, 0.273438, -0.125000, 0.085938}, + {0.093750, 0.101563, -0.070313, 0.046875}, + {-0.015625, 0.125000, 0.046875, -0.031250}, + {-0.007813, 0.273438, 0.054688, 0.000000}, + {0.070313, 0.039063, 0.070313, -0.023438}, + {0.109375, 0.195313, 0.093750, -0.218750}, + {0.046875, 0.078125, 0.039063, 0.070313}, + {0.054688, 0.101563, 0.023438, 0.265625}, + {0.070313, 0.125000, 0.273438, 0.031250}, + {0.093750, 0.335938, 0.164063, 0.132813}, + {0.195313, -0.101563, 0.015625, -0.046875}, + {0.234375, -0.171875, -0.164063, -0.125000}, + {0.296875, -0.085938, -0.117188, 0.031250}, + {0.507813, -0.179688, -0.117188, 0.015625}, + {0.109375, -0.179688, -0.046875, 0.046875}, + {0.132813, -0.054688, -0.039063, 0.070313}, + {0.171875, 0.007813, -0.117188, 0.179688}, + {0.429688, 0.015625, -0.039063, 0.218750}, + {0.132813, -0.015625, 0.156250, -0.085938}, + {0.140625, -0.125000, 0.218750, 0.000000}, + {0.265625, -0.250000, 0.101563, -0.085938}, + {0.382813, -0.109375, 0.101563, -0.125000}, + {0.117188, -0.078125, 0.085938, 0.195313}, + {0.218750, -0.210938, 0.054688, 0.140625}, + {0.265625, -0.031250, 0.054688, 0.148438}, + {0.304688, 0.007813, 0.250000, 0.023438}, + {0.117188, 0.289063, -0.226563, -0.109375}, + {0.132813, 0.023438, -0.195313, -0.132813}, + {0.164063, 0.187500, -0.070313, -0.078125}, + {0.281250, 0.046875, -0.101563, -0.250000}, + {0.164063, 0.023438, -0.023438, -0.039063}, + {0.171875, 0.148438, -0.265625, 0.046875}, + {0.210938, 0.031250, -0.156250, 0.000000}, + {0.390625, 0.179688, -0.101563, -0.031250}, + {0.234375, 0.085938, 0.031250, -0.148438}, + {0.250000, 0.265625, 0.156250, -0.070313}, + {0.312500, 0.054688, 0.093750, -0.007813}, + {0.531250, 0.210938, 0.085938, -0.015625}, + {0.117188, 0.179688, 0.054688, 0.031250}, + {0.132813, 0.039063, 0.140625, 0.070313}, + {0.218750, 0.070313, 0.007813, 0.039063}, + {0.226563, 0.242188, 0.007813, 0.148438} +}; + +/* + * Higher Order Coefficients + */ +const float AmbePlusHOCb5[16][4] = { + {-0.617188, -0.015625, 0.015625, -0.023438}, + {-0.507813, -0.382813, -0.312500, -0.117188}, + {-0.328125, 0.046875, 0.007813, -0.015625}, + {-0.320313, -0.281250, -0.023438, -0.023438}, + {-0.171875, 0.140625, -0.179688, -0.007813}, + {-0.148438, 0.226563, 0.039063, -0.039063}, + {-0.140625, -0.007813, -0.007813, -0.015625}, + {-0.109375, -0.101563, 0.179688, -0.062500}, + {-0.109375, -0.109375, -0.031250, 0.187500}, + {-0.109375, -0.218750, -0.273438, -0.140625}, + {0.007813, -0.007813, -0.015625, -0.015625}, + {0.078125, -0.265625, -0.007813, 0.007813}, + {0.101563, 0.054688, -0.210938, -0.007813}, + {0.164063, 0.242188, 0.093750, 0.039063}, + {0.179688, -0.023438, 0.007813, -0.007813}, + {0.460938, 0.015625, -0.015625, 0.007813} +}; + +/* + * Higher Order Coefficients + */ +const float AmbePlusHOCb6[16][4] = { + {-0.429688, -0.046875, 0.039063, 0.000000}, + {-0.296875, 0.187500, 0.125000, 0.015625}, + {-0.203125, -0.218750, -0.039063, -0.007813}, + {-0.179688, 0.007813, -0.007813, 0.000000}, + {-0.171875, 0.265625, -0.085938, -0.039063}, + {-0.046875, -0.070313, 0.203125, -0.023438}, + {-0.023438, 0.125000, 0.031250, -0.023438}, + {-0.007813, 0.000000, -0.195313, -0.007813}, + {0.007813, -0.046875, -0.007813, -0.015625}, + {0.015625, -0.031250, 0.039063, 0.195313}, + {0.031250, -0.273438, -0.015625, -0.007813}, + {0.140625, 0.257813, 0.015625, 0.007813}, + {0.164063, 0.015625, 0.007813, -0.023438}, + {0.210938, -0.148438, -0.187500, 0.039063}, + {0.273438, -0.179688, 0.054688, -0.007813}, + {0.421875, 0.054688, -0.039063, 0.000000} +}; + +/* + * Higher Order Coefficients + */ +const float AmbePlusHOCb7[16][4] = { + {-0.382813, -0.101563, 0.007813, 0.015625}, + {-0.335938, 0.226563, 0.015625, -0.007813}, + {-0.156250, 0.031250, -0.039063, -0.054688}, + {-0.156250, -0.015625, 0.187500, -0.015625}, + {-0.085938, -0.257813, 0.023438, -0.007813}, + {-0.070313, -0.148438, -0.203125, -0.023438}, + {-0.031250, 0.187500, -0.156250, 0.007813}, + {-0.023438, -0.007813, -0.015625, 0.179688}, + {-0.015625, 0.203125, 0.070313, -0.023438}, + {0.000000, -0.039063, -0.007813, -0.023438}, + {0.140625, -0.078125, 0.179688, -0.007813}, + {0.164063, 0.023438, -0.007813, -0.015625}, + {0.187500, -0.007813, -0.218750, -0.007813}, + {0.218750, 0.242188, 0.023438, 0.031250}, + {0.234375, -0.234375, -0.039063, 0.007813}, + {0.445313, 0.054688, -0.007813, 0.000000} +}; + +/* + * Higher Order Coefficients + */ +const float AmbePlusHOCb8[16][4] = { + {-0.453125, 0.179688, 0.078125, -0.015625}, + {-0.414063, -0.179688, -0.031250, 0.015625}, + {-0.281250, 0.187500, -0.203125, 0.046875}, + {-0.210938, -0.007813, -0.031250, -0.031250}, + {-0.148438, -0.031250, 0.218750, -0.054688}, + {-0.140625, -0.085938, 0.039063, 0.187500}, + {-0.117188, 0.234375, 0.031250, -0.054688}, + {-0.062500, -0.273438, -0.007813, -0.015625}, + {-0.054688, 0.093750, -0.078125, 0.078125}, + {-0.023438, -0.062500, -0.210938, -0.054688}, + {0.023438, 0.000000, 0.023438, -0.046875}, + {0.125000, 0.234375, -0.187500, -0.015625}, + {0.164063, -0.054688, -0.093750, 0.070313}, + {0.187500, 0.179688, 0.093750, 0.015625}, + {0.203125, -0.171875, 0.140625, -0.015625}, + {0.421875, -0.039063, -0.046875, -0.007813} +}; + +#endif // __AMBE3600x2400_CONST_H__ diff --git a/vocoder/ambe3600x2450.c b/vocoder/ambe3600x2450.c new file mode 100644 index 0000000..10cebcc --- /dev/null +++ b/vocoder/ambe3600x2450.c @@ -0,0 +1,600 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - MBE Vocoder + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + */ + +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#define _USE_MATH_DEFINES +#include + +#include "mbe.h" +#include "ambe3600x2450_const.h" + +#ifdef _MSC_VER +#pragma warning(disable: 4244) +#endif +#if defined(__GNUC__) || defined(__GNUG__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#endif + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +/* */ + +int mbe_eccAmbe3600x2450C0(char ambe_fr[4][24]) +{ + int j, errs; + char in[23], out[23]; + + for (j = 0; j < 23; j++) { + in[j] = ambe_fr[0][j + 1]; + } + + errs = mbe_golay2312(in, out); + // ambe_fr[0][0] should be the C0 golay24 parity bit. + // TODO: actually test that here... + for (j = 0; j < 23; j++) { + ambe_fr[0][j + 1] = out[j]; + } + + return (errs); +} + +/* */ + +int mbe_eccAmbe3600x2450Data(char ambe_fr[4][24], char* ambe_d) +{ + int j, errs; + char* ambe, gin[24], gout[24]; + + ambe = ambe_d; + + // just copy C0 + for (j = 23; j > 11; j--) { + *ambe = ambe_fr[0][j]; + ambe++; + } + + // ecc and copy C1 + for (j = 0; j < 23; j++) { + gin[j] = ambe_fr[1][j]; + } + + errs = mbe_golay2312(gin, gout); + for (j = 22; j > 10; j--) { + *ambe = gout[j]; + ambe++; + } + + // just copy C2 + for (j = 10; j >= 0; j--) { + *ambe = ambe_fr[2][j]; + ambe++; + } + + // just copy C3 + for (j = 13; j >= 0; j--) { + *ambe = ambe_fr[3][j]; + ambe++; + } + + return (errs); +} + +/* */ + +int mbe_decodeAmbe2450Parms(char* ambe_d, mbe_parms* cur_mp, mbe_parms* prev_mp) +{ + int ji, i, j, k, l, L, L9, m, am, ak; + int intkl[57]; + int b0, b1, b2, b3, b4, b5, b6, b7, b8; + float f0, Cik[5][18], flokl[57], deltal[57]; + float Sum42, Sum43, Tl[57], Gm[9], Ri[9], sum, c1, c2; + int silence; + int Ji[5], jl; + float deltaGamma, BigGamma; + float unvc, rconst; + + silence = 0; + + // copy repeat from prev_mp + cur_mp->repeat = prev_mp->repeat; + + // decode fundamental frequency w0 from b0 + b0 = 0; + b0 |= ambe_d[0] << 6; + b0 |= ambe_d[1] << 5; + b0 |= ambe_d[2] << 4; + b0 |= ambe_d[3] << 3; + b0 |= ambe_d[37] << 2; + b0 |= ambe_d[38] << 1; + b0 |= ambe_d[39]; + if ((b0 >= 120) && (b0 <= 123)) { + // if w0 bits are 1111000, 1111001, 1111010 or 1111011, frame is erasure +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: Erasure Frame"); +#endif + return (2); + } + else if ((b0 == 124) || (b0 == 125)) { + // if w0 bits are 1111100 or 1111101, frame is silence +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: Silence Frame"); +#endif + silence = 1; + cur_mp->w0 = ((float)2 * M_PI) / (float)32; + f0 = (float)1 / (float)32; + L = 14; + cur_mp->L = 14; + for (l = 1; l <= L; l++) { + cur_mp->Vl[l] = 0; + } + } + else if ((b0 == 126) || (b0 == 127)) { + // if w0 bits are 1111110 or 1111111, frame is tone +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: Tone Frame"); +#endif + return (3); + } + + if (silence == 0) { + // w0 from specification document + f0 = AmbeW0table[b0]; + cur_mp->w0 = f0 * (float)2 * M_PI; + // w0 from patent filings + //f0 = powf (2, ((float) b0 + (float) 195.626) / -(float) 45.368); + //cur_mp->w0 = f0 * (float) 2 *M_PI; + } + + unvc = (float)0.2046 / sqrtf(cur_mp->w0); + //unvc = (float) 1; + //unvc = (float) 0.2046 / sqrtf (f0); + + // decode L + if (silence == 0) { + // L from specification document + // lookup L in tabl3 + L = AmbeLtable[b0]; + // L formula from patent filings + //L=(int)((float)0.4627 / f0); + cur_mp->L = L; + } + L9 = L - 9; + + // decode V/UV parameters + // load b1 from ambe_d + b1 = 0; + b1 |= ambe_d[4] << 4; + b1 |= ambe_d[5] << 3; + b1 |= ambe_d[6] << 2; + b1 |= ambe_d[7] << 1; + b1 |= ambe_d[35]; + + for (l = 1; l <= L; l++) { + // jl from specification document + jl = (int)((float)l * (float)16.0 * f0); + // jl from patent filings? + //jl = (int)(((float)l * (float)16.0 * f0) + 0.25); + + if (silence == 0) + { + cur_mp->Vl[l] = AmbeVuv[b1][jl]; + } +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: jl[%i]:%i Vl[%i]:%i", l, jl, l, cur_mp->Vl[l]); +#endif + } + +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: b0:%i w0:%f L:%i b1:%i\n", b0, cur_mp->w0, L, b1); +#endif + + // decode gain vector + // load b2 from ambe_d + b2 = 0; + b2 |= ambe_d[8] << 4; + b2 |= ambe_d[9] << 3; + b2 |= ambe_d[10] << 2; + b2 |= ambe_d[11] << 1; + b2 |= ambe_d[36]; + + deltaGamma = AmbeDg[b2]; + cur_mp->gamma = deltaGamma + ((float)0.5 * prev_mp->gamma); +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: b2: %i, deltaGamma: %f gamma: %f gamma-1: %f\n", b2, deltaGamma, cur_mp->gamma, prev_mp->gamma); +#endif + + // decode PRBA vectors + Gm[1] = 0; + + // load b3 from ambe_d + b3 = 0; + b3 |= ambe_d[12] << 8; + b3 |= ambe_d[13] << 7; + b3 |= ambe_d[14] << 6; + b3 |= ambe_d[15] << 5; + b3 |= ambe_d[16] << 4; + b3 |= ambe_d[17] << 3; + b3 |= ambe_d[18] << 2; + b3 |= ambe_d[19] << 1; + b3 |= ambe_d[40]; + Gm[2] = AmbePRBA24[b3][0]; + Gm[3] = AmbePRBA24[b3][1]; + Gm[4] = AmbePRBA24[b3][2]; + + // load b4 from ambe_d + b4 = 0; + b4 |= ambe_d[20] << 6; + b4 |= ambe_d[21] << 5; + b4 |= ambe_d[22] << 4; + b4 |= ambe_d[23] << 3; + b4 |= ambe_d[41] << 2; + b4 |= ambe_d[42] << 1; + b4 |= ambe_d[43]; + Gm[5] = AmbePRBA58[b4][0]; + Gm[6] = AmbePRBA58[b4][1]; + Gm[7] = AmbePRBA58[b4][2]; + Gm[8] = AmbePRBA58[b4][3]; + +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: b3: %i Gm[2]: %f Gm[3]: %f Gm[4]: %f b4: %i Gm[5]: %f Gm[6]: %f Gm[7]: %f Gm[8]: %f\n", b3, Gm[2], Gm[3], Gm[4], b4, Gm[5], Gm[6], Gm[7], Gm[8]); +#endif + + // compute Ri + for (i = 1; i <= 8; i++) { + sum = 0; + for (m = 1; m <= 8; m++) { + if (m == 1) { + am = 1; + } + else { + am = 2; + } + sum = sum + ((float)am * Gm[m] * cosf((M_PI * (float)(m - 1) * ((float)i - (float)0.5)) / (float)8)); + } + Ri[i] = sum; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: R%i: %f ", i, Ri[i]); +#endif + } + + // generate first to elements of each Ci,k block from PRBA vector + rconst = ((float)1 / ((float)2 * M_SQRT2)); + Cik[1][1] = (float)0.5 * (Ri[1] + Ri[2]); + Cik[1][2] = rconst * (Ri[1] - Ri[2]); + Cik[2][1] = (float)0.5 * (Ri[3] + Ri[4]); + Cik[2][2] = rconst * (Ri[3] - Ri[4]); + Cik[3][1] = (float)0.5 * (Ri[5] + Ri[6]); + Cik[3][2] = rconst * (Ri[5] - Ri[6]); + Cik[4][1] = (float)0.5 * (Ri[7] + Ri[8]); + Cik[4][2] = rconst * (Ri[7] - Ri[8]); + + // decode HOC + + // load b5 from ambe_d + b5 = 0; + b5 |= ambe_d[24] << 4; + b5 |= ambe_d[25] << 3; + b5 |= ambe_d[26] << 2; + b5 |= ambe_d[27] << 1; + b5 |= ambe_d[44]; + + // load b6 from ambe_d + b6 = 0; + b6 |= ambe_d[28] << 3; + b6 |= ambe_d[29] << 2; + b6 |= ambe_d[30] << 1; + b6 |= ambe_d[45]; + + // load b7 from ambe_d + b7 = 0; + b7 |= ambe_d[31] << 3; + b7 |= ambe_d[32] << 2; + b7 |= ambe_d[33] << 1; + b7 |= ambe_d[46]; + + // load b8 from ambe_d + b8 = 0; + b8 |= ambe_d[34] << 2; + b8 |= ambe_d[47] << 1; + b8 |= ambe_d[48]; + + // lookup Ji + Ji[1] = AmbeLmprbl[L][0]; + Ji[2] = AmbeLmprbl[L][1]; + Ji[3] = AmbeLmprbl[L][2]; + Ji[4] = AmbeLmprbl[L][3]; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: Ji[1]: %i Ji[2]: %i Ji[3]: %i Ji[4]: %i", Ji[1], Ji[2], Ji[3], Ji[4]); + fprintf(stderr, "MBE: AMBE: b5: %i b6: %i b7: %i b8: %i", b5, b6, b7, b8); +#endif + + // Load Ci,k with the values from the HOC tables + // there appear to be a couple typos in eq. 37 so we will just do what makes sense + // (3 <= k <= Ji and k<=6) + for (k = 3; k <= Ji[1]; k++) { + if (k > 6) { + Cik[1][k] = 0; + } + else { + Cik[1][k] = AmbeHOCb5[b5][k - 3]; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: C1,%i: %f ", k, Cik[1][k]); +#endif + } + } + + for (k = 3; k <= Ji[2]; k++) { + if (k > 6) { + Cik[2][k] = 0; + } + else { + Cik[2][k] = AmbeHOCb6[b6][k - 3]; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: C2,%i: %f ", k, Cik[2][k]); +#endif + } + } + + for (k = 3; k <= Ji[3]; k++) { + if (k > 6) { + Cik[3][k] = 0; + } + else { + Cik[3][k] = AmbeHOCb7[b7][k - 3]; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: C3,%i: %f ", k, Cik[3][k]); +#endif + } + } + + for (k = 3; k <= Ji[4]; k++) { + if (k > 6) { + Cik[4][k] = 0; + } + else { + Cik[4][k] = AmbeHOCb8[b8][k - 3]; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: C4,%i: %f ", k, Cik[4][k]); +#endif + } + } + + // inverse DCT each Ci,k to give ci,j (Tl) + l = 1; + for (i = 1; i <= 4; i++) { + ji = Ji[i]; + for (j = 1; j <= ji; j++) { + sum = 0; + for (k = 1; k <= ji; k++) { + if (k == 1) { + ak = 1; + } + else { + ak = 2; + } +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: j: %i Cik[%i][%i]: %f ", j, i, k, Cik[i][k]); +#endif + sum = sum + ((float)ak * Cik[i][k] * cosf((M_PI * (float)(k - 1) * ((float)j - (float)0.5)) / (float)ji)); + } + Tl[l] = sum; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: Tl[%i]: %f", l, Tl[l]); +#endif + l++; + } + } + + // determine log2Ml by applying ci,j to previous log2Ml + + // fix for when L > L(-1) + if (cur_mp->L > prev_mp->L) { + for (l = (prev_mp->L) + 1; l <= cur_mp->L; l++) { + prev_mp->Ml[l] = prev_mp->Ml[prev_mp->L]; + prev_mp->log2Ml[l] = prev_mp->log2Ml[prev_mp->L]; + } + } + + prev_mp->log2Ml[0] = prev_mp->log2Ml[1]; + prev_mp->Ml[0] = prev_mp->Ml[1]; + + // Part 1 + Sum43 = 0; + for (l = 1; l <= cur_mp->L; l++) { + // eq. 40 + flokl[l] = ((float)prev_mp->L / (float)cur_mp->L) * (float)l; + intkl[l] = (int)(flokl[l]); +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: flok%i: %f, intk%i: %i ", l, flokl[l], l, intkl[l]); +#endif + // eq. 41 + deltal[l] = flokl[l] - (float)intkl[l]; +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: delta%i: %f ", l, deltal[l]); +#endif + // eq 43 + Sum43 = Sum43 + ((((float)1 - deltal[l]) * prev_mp->log2Ml[intkl[l]]) + (deltal[l] * prev_mp->log2Ml[intkl[l] + 1])); + } + + Sum43 = (((float)0.65 / (float)cur_mp->L) * Sum43); +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: Sum43: %f", Sum43); +#endif + + // Part 2 + Sum42 = 0; + for (l = 1; l <= cur_mp->L; l++) { + Sum42 += Tl[l]; + } + + Sum42 = Sum42 / (float)cur_mp->L; + BigGamma = cur_mp->gamma - ((float)0.5 * (log((float)cur_mp->L) / log((float)2))) - Sum42; + //BigGamma=cur_mp->gamma - ((float)0.5 * log((float)cur_mp->L)) - Sum42; + + // Part 3 + for (l = 1; l <= cur_mp->L; l++) { + c1 = ((float)0.65 * ((float)1 - deltal[l]) * prev_mp->log2Ml[intkl[l]]); + c2 = ((float)0.65 * deltal[l] * prev_mp->log2Ml[intkl[l] + 1]); + cur_mp->log2Ml[l] = Tl[l] + c1 + c2 - Sum43 + BigGamma; + // inverse log to generate spectral amplitudes + if (cur_mp->Vl[l] == 1) { + cur_mp->Ml[l] = exp((float)0.693 * cur_mp->log2Ml[l]); + } + else { + cur_mp->Ml[l] = unvc * exp((float)0.693 * cur_mp->log2Ml[l]); + } +#ifdef AMBE_DEBUG + fprintf(stderr, "MBE: AMBE: flokl[%i]: %f, intkl[%i]: %i", l, flokl[l], l, intkl[l]); + fprintf(stderr, "MBE: AMBE: deltal[%i]: %f", l, deltal[l]); + fprintf(stderr, "MBE: AMBE: prev_mp->log2Ml[%i]: %f", l, prev_mp->log2Ml[intkl[l]]); + fprintf(stderr, "MBE: AMBE: BigGamma: %f c1: %f c2: %f Sum43: %f Tl[%i]: %f log2Ml[%i]: %f Ml[%i]: %f", BigGamma, c1, c2, Sum43, l, Tl[l], l, cur_mp->log2Ml[l], l, cur_mp->Ml[l]); +#endif + } + + return (0); +} + +/* */ + +void mbe_demodulateAmbe3600x2450Data(char ambe_fr[4][24]) +{ + int i, j, k; + unsigned short pr[115]; + unsigned short foo = 0; + + // create pseudo-random modulator + for (i = 23; i >= 12; i--) { + foo <<= 1; + foo |= ambe_fr[0][i]; + } + + pr[0] = (16 * foo); + for (i = 1; i < 24; i++) { + pr[i] = (173 * pr[i - 1]) + 13849 - (65536 * (((173 * pr[i - 1]) + 13849) / 65536)); + } + + for (i = 1; i < 24; i++) { + pr[i] = pr[i] / 32768; + } + + // demodulate ambe_fr with pr + k = 1; + for (j = 22; j >= 0; j--) { + ambe_fr[1][j] = ((ambe_fr[1][j]) ^ pr[k]); + k++; + } +} + +/* */ + +void mbe_processAmbe2450DataF(float* aout_buf, int* errs, int* errs2, char* err_str, char ambe_d[49], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality) +{ + int i, bad; + + for (i = 0; i < *errs2; i++) { + *err_str = '='; + err_str++; + } + + bad = mbe_decodeAmbe2450Parms(ambe_d, cur_mp, prev_mp); + if (bad == 2) { + // Erasure frame + *err_str = 'E'; + err_str++; + cur_mp->repeat = 0; + } + else if (bad == 3) { + // Tone Frame + *err_str = 'T'; + err_str++; + cur_mp->repeat = 0; + } + else if (*errs2 > 3) { + mbe_useLastMbeParms(cur_mp, prev_mp); + cur_mp->repeat++; + *err_str = 'R'; + err_str++; + } + else { + cur_mp->repeat = 0; + } + + if (bad == 0) { + if (cur_mp->repeat <= 3) { + mbe_moveMbeParms(cur_mp, prev_mp); + mbe_spectralAmpEnhance(cur_mp); + mbe_synthesizeSpeechF(aout_buf, cur_mp, prev_mp_enhanced, uvquality); + mbe_moveMbeParms(cur_mp, prev_mp_enhanced); + } + else { + *err_str = 'M'; + err_str++; + mbe_synthesizeSilenceF(aout_buf); + mbe_initMbeParms(cur_mp, prev_mp, prev_mp_enhanced); + } + } + else { + mbe_synthesizeSilenceF(aout_buf); + mbe_initMbeParms(cur_mp, prev_mp, prev_mp_enhanced); + } + + *err_str = 0; +} + +/* */ + +void mbe_processAmbe2450Data(short* aout_buf, int* errs, int* errs2, char* err_str, char ambe_d[49], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality) +{ + float float_buf[160]; + mbe_processAmbe2450DataF(float_buf, errs, errs2, err_str, ambe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality); + mbe_floatToShort(float_buf, aout_buf); +} + +/* */ + +void mbe_processAmbe3600x2450FrameF(float* aout_buf, int* errs, int* errs2, char* err_str, char ambe_fr[4][24], char ambe_d[49], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality) +{ + *errs = 0; + *errs2 = 0; + *errs = mbe_eccAmbe3600x2450C0(ambe_fr); + mbe_demodulateAmbe3600x2450Data(ambe_fr); + + *errs2 = *errs; + *errs2 += mbe_eccAmbe3600x2450Data(ambe_fr, ambe_d); + + mbe_processAmbe2450DataF(aout_buf, errs, errs2, err_str, ambe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality); +} + +/* */ + +void mbe_processAmbe3600x2450Frame(short* aout_buf, int* errs, int* errs2, char* err_str, char ambe_fr[4][24], char ambe_d[49], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality) +{ + float float_buf[160]; + mbe_processAmbe3600x2450FrameF(float_buf, errs, errs2, err_str, ambe_fr, ambe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality); + mbe_floatToShort(float_buf, aout_buf); +} diff --git a/vocoder/ambe3600x2450_const.h b/vocoder/ambe3600x2450_const.h new file mode 100644 index 0000000..ed456a5 --- /dev/null +++ b/vocoder/ambe3600x2450_const.h @@ -0,0 +1,991 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - MBE Vocoder + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + */ +/** + * @file ambe3600x2450_const.h + * @ingroup vocoder + */ + +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#if !defined(__AMBE3600x2450_CONST_H__) +#define __AMBE3600x2450_CONST_H__ + +#ifdef _MSC_VER +#pragma warning(disable: 4305) +#endif + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +/* + * Fundamental Frequency Quanitization Table + */ + +const float AmbeW0table[120] = { + 0.049971, 0.049215, 0.048471, 0.047739, 0.047010, 0.046299, + 0.045601, 0.044905, 0.044226, 0.043558, 0.042900, 0.042246, + 0.041609, 0.040979, 0.040356, 0.039747, 0.039148, 0.038559, + 0.037971, 0.037399, 0.036839, 0.036278, 0.035732, 0.035198, + 0.034672, 0.034145, 0.033636, 0.033133, 0.032635, 0.032148, + 0.031670, 0.031122, 0.030647, 0.030184, 0.029728, 0.029272, + 0.028831, 0.028395, 0.027966, 0.027538, + 0.027122, 0.026712, 0.026304, 0.025906, 0.025515, 0.025129, + 0.024746, 0.024372, 0.024002, 0.023636, 0.023279, 0.022926, + 0.022581, 0.022236, 0.021900, 0.021570, 0.021240, 0.020920, + 0.020605, 0.020294, 0.019983, 0.019684, 0.019386, 0.019094, + 0.018805, 0.018520, 0.018242, 0.017965, 0.017696, 0.017431, + 0.017170, 0.016911, 0.016657, 0.016409, 0.016163, 0.015923, + 0.015686, 0.015411, 0.015177, 0.014946, + 0.014721, 0.014496, 0.014277, 0.014061, 0.013847, 0.013636, + 0.013430, 0.013227, 0.013025, 0.012829, 0.012634, 0.012444, + 0.012253, 0.012068, 0.011887, 0.011703, 0.011528, 0.011353, + 0.011183, 0.011011, 0.010845, 0.010681, 0.010517, 0.010359, + 0.010202, 0.010050, 0.009895, 0.009747, 0.009600, 0.009453, + 0.009312, 0.009172, 0.009033, 0.008896, 0.008762, 0.008633, + 0.008501, 0.008375, 0.008249, 0.008125 +}; + +const float AmbeLtable[120] = { + 9, 9, 9, 9, 9, 9, + 10, 10, 10, 10, 10, 10, + 11, 11, 11, 11, 11, 11, + 12, 12, 12, 12, 12, 13, + 13, 13, 13, 13, 14, 14, + 14, 14, 15, 15, 15, 15, + 16, 16, 16, 16, 17, 17, + 17, 17, 18, 18, 18, 18, + 19, 19, 19, 20, 20, 20, + 21, 21, 21, 22, 22, 22, + 23, 23, 23, 24, 24, 24, + 25, 25, 26, 26, 26, 27, + 27, 28, 28, 29, 29, 30, + 30, 30, 31, 31, 32, 32, + 33, 33, 34, 34, 35, 36, + 36, 37, 37, 38, 38, 39, + 40, 40, 41, 42, 42, 43, + 43, 44, 45, 46, 46, 47, + 48, 48, 49, 50, 51, 52, + 52, 53, 54, 55, 56, 56 +}; + +/* + * V/UV Quantization Vectors + */ +const int AmbeVuv[32][8] = { + {1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 0}, + {1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 0, 0}, + {1, 1, 0, 1, 1, 1, 1, 1}, + {1, 1, 1, 0, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 0, 1, 1}, + {1, 1, 1, 1, 0, 0, 0, 0}, + {1, 1, 1, 1, 1, 0, 0, 0}, + {1, 1, 1, 0, 0, 0, 0, 0}, + {1, 1, 1, 0, 0, 0, 0, 1}, + {1, 1, 0, 0, 0, 0, 0, 0}, + {1, 1, 1, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, + {1, 1, 1, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0} +}; + +/* + * V/UV Quantization Vectors + * alternate version + */ +/* +const int AmbeVuv[32][8] = { + {1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 0}, + {1, 1, 1, 1, 1, 1, 1, 0}, + {1, 1, 1, 1, 1, 1, 0, 0}, + {1, 1, 0, 1, 1, 1, 1, 1}, + {1, 1, 1, 0, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 0, 1, 1}, + {1, 1, 1, 1, 0, 0, 0, 0}, + {1, 1, 1, 1, 1, 0, 0, 0}, + {1, 1, 1, 0, 0, 0, 0, 0}, + {1, 1, 1, 0, 0, 0, 0, 1}, + {1, 1, 0, 0, 0, 0, 0, 0}, + {1, 1, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0} +}; +*/ + +/* + * Log Magnitude Prediction Residual Block Lengths + */ +const int AmbeLmprbl[57][4] = { + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {0, 0, 0, 0,}, + {2, 2, 2, 3,}, + {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} +}; + +/* + * Gain Quantizer Levels + */ +const float AmbeDg[32] = { + -2.0, -0.67, 0.297941, 0.663728, 1.036829, 1.438136, 1.890077, 2.227970, + 2.478289, 2.667544, 2.793619, 2.893261, 3.020630, 3.138586, 3.237579, 3.322570, + 3.432367, 3.571863, 3.696650, 3.814917, 3.920932, 4.022503, 4.123569, 4.228291, + 4.370569, 4.543700, 4.707695, 4.848879, 5.056757, 5.326468, 5.777581, 6.874496 +}; + +/* + * PRBA24 Vector Quantizer Levels + */ +const float AmbePRBA24[512][3] = { + {0.526055, -0.328567, -0.304727}, + {0.441044, -0.303127, -0.201114}, + {1.030896, -0.324730, -0.397204}, + {0.839696, -0.351933, -0.224909}, + {0.272958, -0.176118, -0.098893}, + {0.221466, -0.160045, -0.061026}, + {0.496555, -0.211499, 0.047305}, + {0.424376, -0.223752, 0.069911}, + {0.264531, -0.353355, -0.330505}, + {0.273650, -0.253004, -0.250241}, + {0.484531, -0.297627, -0.071051}, + {0.410814, -0.224961, -0.084998}, + {0.039519, -0.252904, -0.115128}, + {0.017423, -0.296519, -0.045921}, + {0.225113, -0.224371, 0.037882}, + {0.183424, -0.260492, 0.050491}, + {0.308704, -0.073205, -0.405880}, + {0.213125, -0.101632, -0.333208}, + {0.617735, -0.137299, -0.213670}, + {0.514382, -0.126485, -0.170204}, + {0.130009, -0.076955, -0.229303}, + {0.061740, -0.108259, -0.203887}, + {0.244473, -0.110094, -0.051689}, + {0.230452, -0.076147, -0.028190}, + {0.059837, -0.254595, -0.562704}, + {0.011630, -0.135223, -0.432791}, + {0.207077, -0.152248, -0.148391}, + {0.158078, -0.128800, -0.122150}, + {-0.265982, -0.144742, -0.199894}, + {-0.356479, -0.204740, -0.156465}, + {0.000324, -0.139549, -0.066471}, + {0.001888, -0.170557, -0.025025}, + {0.402913, -0.581478, -0.274626}, + {0.191289, -0.540335, -0.193040}, + {0.632914, -0.401410, -0.006636}, + {0.471086, -0.463144, 0.061489}, + {0.044829, -0.438487, 0.033433}, + {0.015513, -0.539475, -0.006719}, + {0.336218, -0.351311, 0.214087}, + {0.239967, -0.380836, 0.157681}, + {0.347609, -0.901619, -0.688432}, + {0.064067, -0.826753, -0.492089}, + {0.303089, -0.396757, -0.108446}, + {0.235590, -0.446122, 0.006437}, + {-0.236964, -0.652532, -0.135520}, + {-0.418285, -0.793014, -0.034730}, + {-0.038262, -0.516984, 0.273681}, + {-0.037419, -0.958198, 0.214749}, + {0.061624, -0.238233, -0.237184}, + {-0.013944, -0.235704, -0.204811}, + {0.286428, -0.210542, -0.029587}, + {0.257656, -0.261837, -0.056566}, + {-0.235852, -0.310760, -0.165147}, + {-0.334949, -0.385870, -0.197362}, + {0.094870, -0.241144, 0.059122}, + {0.060177, -0.225884, 0.031140}, + {-0.301184, -0.306545, -0.446189}, + {-0.293528, -0.504146, -0.429844}, + {-0.055084, -0.379015, -0.125887}, + {-0.115434, -0.375008, -0.059939}, + {-0.777425, -0.592163, -0.107585}, + {-0.950500, -0.893847, -0.181762}, + {-0.259402, -0.396726, 0.010357}, + {-0.368905, -0.449026, 0.038299}, + {0.279719, -0.063196, -0.184628}, + {0.255265, -0.067248, -0.121124}, + {0.458433, -0.103777, 0.010074}, + {0.437231, -0.092496, -0.031028}, + {0.082265, -0.028050, -0.041262}, + {0.045920, -0.051719, -0.030155}, + {0.271149, -0.043613, 0.112085}, + {0.246881, -0.065274, 0.105436}, + {0.056590, -0.117773, -0.142283}, + {0.058824, -0.104418, -0.099608}, + {0.213781, -0.111974, 0.031269}, + {0.187554, -0.070340, 0.011834}, + {-0.185701, -0.081106, -0.073803}, + {-0.266112, -0.074133, -0.085370}, + {-0.029368, -0.046490, 0.124679}, + {-0.017378, -0.102882, 0.140482}, + {0.114700, 0.092738, -0.244271}, + {0.072922, 0.007863, -0.231476}, + {0.270022, 0.031819, -0.094208}, + {0.254403, 0.024805, -0.050389}, + {-0.182905, 0.021629, -0.168481}, + {-0.225864, -0.010109, -0.130374}, + {0.040089, 0.013969, 0.016028}, + {0.001442, 0.010551, 0.032942}, + {-0.287472, -0.036130, -0.296798}, + {-0.332344, -0.108862, -0.342196}, + {0.012700, 0.022917, -0.052501}, + {-0.040681, -0.001805, -0.050548}, + {-0.718522, -0.061234, -0.278820}, + {-0.879205, -0.213588, -0.303508}, + {-0.234102, -0.065407, 0.013686}, + {-0.281223, -0.076139, 0.046830}, + {0.141967, -0.193679, -0.055697}, + {0.100318, -0.161222, -0.063062}, + {0.265859, -0.132747, 0.078209}, + {0.244805, -0.139776, 0.122123}, + {-0.121802, -0.179976, 0.031732}, + {-0.185318, -0.214011, 0.018117}, + {0.047014, -0.153961, 0.218068}, + {0.047305, -0.187402, 0.282114}, + {-0.027533, -0.415868, -0.333841}, + {-0.125886, -0.334492, -0.290317}, + {-0.030602, -0.190918, 0.097454}, + {-0.054936, -0.209948, 0.158977}, + {-0.507223, -0.295876, -0.217183}, + {-0.581733, -0.403194, -0.208936}, + {-0.299719, -0.289679, 0.297101}, + {-0.363169, -0.362718, 0.436529}, + {-0.124627, -0.042100, -0.157011}, + {-0.161571, -0.092846, -0.183636}, + {0.084520, -0.100217, -0.000901}, + {0.055655, -0.136381, 0.032764}, + {-0.545087, -0.197713, -0.026888}, + {-0.662772, -0.179815, 0.026419}, + {-0.165583, -0.148913, 0.090382}, + {-0.240772, -0.182830, 0.105474}, + {-0.576315, -0.359473, -0.456844}, + {-0.713430, -0.554156, -0.476739}, + {-0.275628, -0.223640, -0.051584}, + {-0.359501, -0.230758, -0.027006}, + {-1.282559, -0.284807, -0.233743}, + {-1.060476, -0.399911, -0.562698}, + {-0.871952, -0.272197, 0.016126}, + {-0.747922, -0.329404, 0.276696}, + {0.643086, 0.046175, -0.660078}, + {0.738204, -0.127844, -0.433708}, + {1.158072, 0.025571, -0.177856}, + {0.974840, -0.009417, -0.112337}, + {0.418014, 0.032741, -0.124545}, + {0.381422, -0.001557, -0.085504}, + {0.768280, 0.056085, 0.095375}, + {0.680004, 0.052035, 0.152318}, + {0.473182, 0.012560, -0.264221}, + {0.345153, 0.036627, -0.248756}, + {0.746238, -0.025880, -0.106050}, + {0.644319, -0.058256, -0.095133}, + {0.185924, -0.022230, -0.070540}, + {0.146068, -0.009550, -0.057871}, + {0.338488, 0.013022, 0.069961}, + {0.298969, 0.047403, 0.052598}, + {0.346002, 0.256253, -0.380261}, + {0.313092, 0.163821, -0.314004}, + {0.719154, 0.103108, -0.252648}, + {0.621429, 0.172423, -0.265180}, + {0.240461, 0.104684, -0.202582}, + {0.206946, 0.139642, -0.138016}, + {0.359915, 0.101273, -0.052997}, + {0.318117, 0.125888, -0.003486}, + {0.150452, 0.050219, -0.409155}, + {0.188753, 0.091894, -0.325733}, + {0.334922, 0.029098, -0.098587}, + {0.324508, 0.015809, -0.135408}, + {-0.042506, 0.038667, -0.208535}, + {-0.083003, 0.094758, -0.174054}, + {0.094773, 0.102653, -0.025701}, + {0.063284, 0.118703, -0.000071}, + {0.355965, -0.139239, -0.191705}, + {0.392742, -0.105496, -0.132103}, + {0.663678, -0.204627, -0.031242}, + {0.609381, -0.146914, 0.079610}, + {0.151855, -0.132843, -0.007125}, + {0.146404, -0.161917, 0.024842}, + {0.400524, -0.135221, 0.232289}, + {0.324931, -0.116605, 0.253458}, + {0.169066, -0.215132, -0.185604}, + {0.128681, -0.189394, -0.160279}, + {0.356194, -0.116992, -0.038381}, + {0.342866, -0.144687, 0.020265}, + {-0.065545, -0.202593, -0.043688}, + {-0.124296, -0.260225, -0.035370}, + {0.083224, -0.235149, 0.153301}, + {0.046256, -0.309608, 0.190944}, + {0.187385, -0.008168, -0.198575}, + {0.190401, -0.018699, -0.136858}, + {0.398009, -0.025700, -0.007458}, + {0.346948, -0.022258, -0.020905}, + {-0.047064, -0.085629, -0.080677}, + {-0.067523, -0.128972, -0.119538}, + {0.186086, -0.016828, 0.070014}, + {0.187364, 0.017133, 0.075949}, + {-0.112669, -0.037433, -0.298944}, + {-0.068276, -0.114504, -0.265795}, + {0.147510, -0.040616, -0.013687}, + {0.133084, -0.062849, -0.032637}, + {-0.416571, -0.041544, -0.125088}, + {-0.505337, -0.044193, -0.157651}, + {-0.154132, -0.075106, 0.050466}, + {-0.148036, -0.059719, 0.121516}, + {0.490555, 0.157659, -0.222208}, + {0.436700, 0.120500, -0.205869}, + {0.754525, 0.269323, 0.045810}, + {0.645077, 0.271923, 0.013942}, + {0.237023, 0.115337, -0.026429}, + {0.204895, 0.121020, -0.008541}, + {0.383999, 0.153963, 0.171763}, + {0.385026, 0.222074, 0.239731}, + {0.198232, 0.072972, -0.108179}, + {0.147882, 0.074743, -0.123341}, + {0.390929, 0.075205, 0.081828}, + {0.341623, 0.089405, 0.069389}, + {-0.003381, 0.159694, -0.016026}, + {-0.043653, 0.206860, -0.040729}, + {0.135515, 0.107824, 0.179310}, + {0.081086, 0.119673, 0.174282}, + {0.192637, 0.400335, -0.341906}, + {0.171196, 0.284921, -0.221516}, + {0.377807, 0.359087, -0.151523}, + {0.411052, 0.297925, -0.099774}, + {-0.010060, 0.261887, -0.149567}, + {-0.107877, 0.287756, -0.116982}, + {0.158003, 0.209727, 0.077988}, + {0.109710, 0.232272, 0.088135}, + {0.000698, 0.209353, -0.395208}, + {-0.094015, 0.230322, -0.279928}, + {0.137355, 0.230881, -0.124115}, + {0.103058, 0.166855, -0.100386}, + {-0.305058, 0.305422, -0.176026}, + {-0.422049, 0.337137, -0.293297}, + {-0.121744, 0.185124, 0.048115}, + {-0.171052, 0.200312, 0.052812}, + {0.224091, -0.010673, -0.019727}, + {0.200266, -0.020167, 0.001798}, + {0.382742, 0.032362, 0.161665}, + {0.345631, -0.019705, 0.164451}, + {0.029431, 0.045010, 0.071518}, + {0.031940, 0.010876, 0.087037}, + {0.181935, 0.039112, 0.202316}, + {0.181810, 0.033189, 0.253435}, + {-0.008677, -0.066679, -0.144737}, + {-0.021768, -0.021288, -0.125903}, + {0.136766, 0.000100, 0.059449}, + {0.135405, -0.020446, 0.103793}, + {-0.289115, 0.039747, -0.012256}, + {-0.338683, 0.025909, -0.034058}, + {-0.016515, 0.048584, 0.197981}, + {-0.046790, 0.011816, 0.199964}, + {0.094214, 0.127422, -0.169936}, + {0.048279, 0.096189, -0.148153}, + {0.217391, 0.081732, 0.013677}, + {0.179656, 0.084671, 0.031434}, + {-0.227367, 0.118176, -0.039803}, + {-0.327096, 0.159747, -0.018931}, + {0.000834, 0.113118, 0.125325}, + {-0.014617, 0.128924, 0.163776}, + {-0.254570, 0.154329, -0.232018}, + {-0.353068, 0.124341, -0.174409}, + {-0.061004, 0.107744, 0.037257}, + {-0.100991, 0.080302, 0.062701}, + {-0.927022, 0.285660, -0.240549}, + {-1.153224, 0.277232, -0.322538}, + {-0.569012, 0.108135, 0.172634}, + {-0.555273, 0.131461, 0.325930}, + {0.518847, 0.065683, -0.132877}, + {0.501324, -0.006585, -0.094884}, + {1.066190, -0.150380, 0.201791}, + {0.858377, -0.166415, 0.081686}, + {0.320584, -0.031499, 0.039534}, + {0.311442, -0.075120, 0.026013}, + {0.625829, -0.019856, 0.346041}, + {0.525271, -0.003948, 0.284868}, + {0.312594, -0.075673, -0.066642}, + {0.295732, -0.057895, -0.042207}, + {0.550446, -0.029110, 0.046850}, + {0.465467, -0.068987, 0.096167}, + {0.122669, -0.051786, 0.044283}, + {0.079669, -0.044145, 0.045805}, + {0.238778, -0.031835, 0.171694}, + {0.200734, -0.072619, 0.178726}, + {0.342512, 0.131270, -0.163021}, + {0.294028, 0.111759, -0.125793}, + {0.589523, 0.121808, -0.049372}, + {0.550506, 0.132318, 0.017485}, + {0.164280, 0.047560, -0.058383}, + {0.120110, 0.049242, -0.052403}, + {0.269181, 0.035000, 0.103494}, + {0.297466, 0.038517, 0.139289}, + {0.094549, -0.030880, -0.153376}, + {0.080363, 0.024359, -0.127578}, + {0.281351, 0.055178, 0.000155}, + {0.234900, 0.039477, 0.013957}, + {-0.118161, 0.011976, -0.034270}, + {-0.157654, 0.027765, -0.005010}, + {0.102631, 0.027283, 0.099723}, + {0.077285, 0.052532, 0.115583}, + {0.329398, -0.278552, 0.016316}, + {0.305993, -0.267896, 0.094952}, + {0.775270, -0.394995, 0.290748}, + {0.583180, -0.252159, 0.285391}, + {0.192226, -0.182242, 0.126859}, + {0.185908, -0.245779, 0.159940}, + {0.346293, -0.250404, 0.355682}, + {0.354160, -0.364521, 0.472337}, + {0.134942, -0.313666, -0.115181}, + {0.126077, -0.286568, -0.039927}, + {0.405618, -0.211792, 0.199095}, + {0.312099, -0.213642, 0.190972}, + {-0.071392, -0.297366, 0.081426}, + {-0.165839, -0.301986, 0.160640}, + {0.147808, -0.290712, 0.298198}, + {0.063302, -0.310149, 0.396302}, + {0.141444, -0.081377, -0.076621}, + {0.115936, -0.104440, -0.039885}, + {0.367023, -0.087281, 0.096390}, + {0.330038, -0.117958, 0.127050}, + {0.002897, -0.062454, 0.025151}, + {-0.052404, -0.082200, 0.041975}, + {0.181553, -0.137004, 0.230489}, + {0.140768, -0.094604, 0.265928}, + {-0.101763, -0.209566, -0.135964}, + {-0.159056, -0.191005, -0.095509}, + {0.045016, -0.081562, 0.075942}, + {0.016808, -0.112482, 0.068593}, + {-0.408578, -0.132377, 0.079163}, + {-0.431534, -0.214646, 0.157714}, + {-0.096931, -0.101938, 0.200304}, + {-0.167867, -0.114851, 0.262964}, + {0.393882, 0.086002, 0.008961}, + {0.338747, 0.048405, -0.004187}, + {0.877844, 0.374373, 0.171008}, + {0.740790, 0.324525, 0.242248}, + {0.200218, 0.070150, 0.085891}, + {0.171760, 0.090531, 0.102579}, + {0.314263, 0.126417, 0.322833}, + {0.313523, 0.065445, 0.403855}, + {0.164261, 0.057745, -0.005490}, + {0.122141, 0.024122, 0.009190}, + {0.308248, 0.078401, 0.180577}, + {0.251222, 0.073868, 0.160457}, + {-0.047526, 0.023725, 0.086336}, + {-0.091643, 0.005539, 0.093179}, + {0.079339, 0.044135, 0.206697}, + {0.104213, 0.011277, 0.240060}, + {0.226607, 0.186234, -0.056881}, + {0.173281, 0.158131, -0.059413}, + {0.339400, 0.214501, 0.052905}, + {0.309166, 0.188181, 0.058028}, + {0.014442, 0.194715, 0.048945}, + {-0.028793, 0.194766, 0.089078}, + {0.069564, 0.206743, 0.193568}, + {0.091532, 0.202786, 0.269680}, + {-0.071196, 0.135604, -0.103744}, + {-0.118288, 0.152837, -0.060151}, + {0.146856, 0.143174, 0.061789}, + {0.104379, 0.143672, 0.056797}, + {-0.541832, 0.250034, -0.017602}, + {-0.641583, 0.278411, -0.111909}, + {-0.094447, 0.159393, 0.164848}, + {-0.113612, 0.120702, 0.221656}, + {0.204918, -0.078894, 0.075524}, + {0.161232, -0.090256, 0.088701}, + {0.378460, -0.033687, 0.309964}, + {0.311701, -0.049984, 0.316881}, + {0.019311, -0.050048, 0.212387}, + {0.002473, -0.062855, 0.278462}, + {0.151448, -0.090652, 0.410031}, + {0.162778, -0.071291, 0.531252}, + {-0.083704, -0.076839, -0.020798}, + {-0.092832, -0.043492, 0.029202}, + {0.136844, -0.077791, 0.186493}, + {0.089536, -0.086826, 0.184711}, + {-0.270255, -0.058858, 0.173048}, + {-0.350416, -0.009219, 0.273260}, + {-0.105248, -0.205534, 0.425159}, + {-0.135030, -0.197464, 0.623550}, + {-0.051717, 0.069756, -0.043829}, + {-0.081050, 0.056947, -0.000205}, + {0.190388, 0.016366, 0.145922}, + {0.142662, 0.002575, 0.159182}, + {-0.352890, 0.011117, 0.091040}, + {-0.367374, 0.056547, 0.147209}, + {-0.003179, 0.026570, 0.282541}, + {-0.069934, -0.005171, 0.337678}, + {-0.496181, 0.026464, 0.019432}, + {-0.690384, 0.069313, -0.004175}, + {-0.146138, 0.046372, 0.161839}, + {-0.197581, 0.034093, 0.241003}, + {-0.989567, 0.040993, 0.049384}, + {-1.151075, 0.210556, 0.237374}, + {-0.335366, -0.058208, 0.480168}, + {-0.502419, -0.093761, 0.675240}, + {0.862548, 0.264137, -0.294905}, + {0.782668, 0.251324, -0.122108}, + {1.597797, 0.463818, -0.133153}, + {1.615756, 0.060653, 0.084764}, + {0.435588, 0.209832, 0.095050}, + {0.431013, 0.165328, 0.047909}, + {1.248164, 0.265923, 0.488086}, + {1.009933, 0.345440, 0.473702}, + {0.477017, 0.194237, -0.058012}, + {0.401362, 0.186915, -0.054137}, + {1.202158, 0.284782, -0.066531}, + {1.064907, 0.203766, 0.046383}, + {0.255848, 0.133398, 0.046049}, + {0.218680, 0.128833, 0.065326}, + {0.490817, 0.182041, 0.286583}, + {0.440714, 0.106576, 0.301120}, + {0.604263, 0.522925, -0.238629}, + {0.526329, 0.377577, -0.198100}, + {1.038632, 0.606242, -0.121253}, + {0.995283, 0.552202, 0.110700}, + {0.262232, 0.313664, -0.086909}, + {0.230835, 0.273385, -0.054268}, + {0.548466, 0.490721, 0.278201}, + {0.466984, 0.355859, 0.289160}, + {0.367137, 0.236160, -0.228114}, + {0.309359, 0.233843, -0.171325}, + {0.465268, 0.276569, 0.010951}, + {0.378124, 0.250237, 0.011131}, + {0.061885, 0.296810, -0.011420}, + {0.000125, 0.350029, -0.011277}, + {0.163815, 0.261191, 0.175863}, + {0.165132, 0.308797, 0.227800}, + {0.461418, 0.052075, -0.016543}, + {0.472372, 0.046962, 0.045746}, + {0.856406, 0.136415, 0.245074}, + {0.834616, 0.003254, 0.372643}, + {0.337869, 0.036994, 0.232513}, + {0.267414, 0.027593, 0.252779}, + {0.584983, 0.113046, 0.583119}, + {0.475406, -0.024234, 0.655070}, + {0.264823, -0.029292, 0.004270}, + {0.246071, -0.019109, 0.030048}, + {0.477401, 0.021039, 0.155448}, + {0.458453, -0.043959, 0.187850}, + {0.067059, -0.061227, 0.126904}, + {0.044608, -0.034575, 0.150205}, + {0.191304, -0.003810, 0.316776}, + {0.153078, 0.029915, 0.361303}, + {0.320704, 0.178950, -0.088835}, + {0.300866, 0.137645, -0.056893}, + {0.553442, 0.162339, 0.131987}, + {0.490083, 0.123682, 0.146163}, + {0.118950, 0.083109, 0.034052}, + {0.099344, 0.066212, 0.054329}, + {0.228325, 0.122445, 0.309219}, + {0.172093, 0.135754, 0.323361}, + {0.064213, 0.063405, -0.058243}, + {0.011906, 0.088795, -0.069678}, + {0.194232, 0.129185, 0.125708}, + {0.155182, 0.174013, 0.144099}, + {-0.217068, 0.112731, 0.093497}, + {-0.307590, 0.171146, 0.110735}, + {-0.014897, 0.138094, 0.232455}, + {-0.036936, 0.170135, 0.279166}, + {0.681886, 0.437121, 0.078458}, + {0.548559, 0.376914, 0.092485}, + {1.259194, 0.901494, 0.256085}, + {1.296139, 0.607949, 0.302184}, + {0.319619, 0.307231, 0.099647}, + {0.287232, 0.359355, 0.186844}, + {0.751306, 0.676688, 0.499386}, + {0.479609, 0.553030, 0.560447}, + {0.276377, 0.214032, -0.003661}, + {0.238146, 0.223595, 0.028806}, + {0.542688, 0.266205, 0.171393}, + {0.460188, 0.283979, 0.158288}, + {0.057385, 0.309853, 0.144517}, + {-0.006881, 0.348152, 0.097310}, + {0.244434, 0.247298, 0.322601}, + {0.253992, 0.335420, 0.402241}, + {0.354006, 0.579776, -0.130176}, + {0.267043, 0.461976, -0.058178}, + {0.534049, 0.626549, 0.046747}, + {0.441835, 0.468260, 0.057556}, + {0.110477, 0.628795, 0.102950}, + {0.031409, 0.489068, 0.090605}, + {0.229564, 0.525640, 0.325454}, + {0.105570, 0.582151, 0.509738}, + {0.005690, 0.521474, -0.157885}, + {0.104463, 0.424022, -0.080647}, + {0.223784, 0.389860, 0.060904}, + {0.159806, 0.340571, 0.062061}, + {-0.173976, 0.573425, 0.027383}, + {-0.376008, 0.587868, 0.133042}, + {-0.051773, 0.348339, 0.231923}, + {-0.122571, 0.473049, 0.251159}, + {0.324321, 0.148510, 0.116006}, + {0.282263, 0.121730, 0.114016}, + {0.690108, 0.256346, 0.418128}, + {0.542523, 0.294427, 0.461973}, + {0.056944, 0.107667, 0.281797}, + {0.027844, 0.106858, 0.355071}, + {0.160456, 0.177656, 0.528819}, + {0.227537, 0.177976, 0.689465}, + {0.111585, 0.097896, 0.109244}, + {0.083994, 0.133245, 0.115789}, + {0.208740, 0.142084, 0.208953}, + {0.156072, 0.143303, 0.231368}, + {-0.185830, 0.214347, 0.309774}, + {-0.311053, 0.240517, 0.328512}, + {-0.041749, 0.090901, 0.511373}, + {-0.156164, 0.098486, 0.478020}, + {0.151543, 0.263073, -0.033471}, + {0.126322, 0.213004, -0.007014}, + {0.245313, 0.217564, 0.120210}, + {0.259136, 0.225542, 0.176601}, + {-0.190632, 0.260214, 0.141755}, + {-0.189271, 0.331768, 0.170606}, + {0.054763, 0.294766, 0.357775}, + {-0.033724, 0.257645, 0.365069}, + {-0.184971, 0.396532, 0.057728}, + {-0.293313, 0.400259, 0.001123}, + {-0.015219, 0.232287, 0.177913}, + {-0.022524, 0.244724, 0.240753}, + {-0.520342, 0.347950, 0.249265}, + {-0.671997, 0.410782, 0.153434}, + {-0.253089, 0.412356, 0.489854}, + {-0.410922, 0.562454, 0.543891} +}; + +/* + * PRBA58 Vector Quantizer Levels + */ +const float AmbePRBA58[128][4] = { + {-0.103660, 0.094597, -0.013149, 0.081501}, + {-0.170709, 0.129958, -0.057316, 0.112324}, + {-0.095113, 0.080892, -0.027554, 0.003371}, + {-0.154153, 0.113437, -0.074522, 0.003446}, + {-0.109553, 0.153519, 0.006858, 0.040930}, + {-0.181931, 0.217882, -0.019042, 0.040049}, + {-0.096246, 0.144191, -0.024147, -0.035120}, + {-0.174811, 0.193357, -0.054261, -0.071700}, + {-0.183241, -0.052840, 0.117923, 0.030960}, + {-0.242634, 0.009075, 0.098007, 0.091643}, + {-0.143847, -0.028529, 0.040171, -0.002812}, + {-0.198809, 0.006990, 0.020668, 0.026641}, + {-0.233172, -0.028793, 0.140130, -0.071927}, + {-0.309313, 0.056873, 0.108262, -0.018930}, + {-0.172782, -0.002037, 0.048755, -0.087065}, + {-0.242901, 0.036076, 0.015064, -0.064366}, + {0.077107, 0.172685, 0.159939, 0.097456}, + {0.024820, 0.209676, 0.087347, 0.105204}, + {0.085113, 0.151639, 0.084272, 0.022747}, + {0.047975, 0.196695, 0.038770, 0.029953}, + {0.113925, 0.236813, 0.176121, 0.016635}, + {0.009708, 0.267969, 0.127660, 0.015872}, + {0.114044, 0.202311, 0.096892, -0.043071}, + {0.047219, 0.260395, 0.050952, -0.046996}, + {-0.055095, 0.034041, 0.200464, 0.039050}, + {-0.061582, 0.069566, 0.113048, 0.027511}, + {-0.025469, 0.040440, 0.132777, -0.039098}, + {-0.031388, 0.064010, 0.067559, -0.017117}, + {-0.074386, 0.086579, 0.228232, -0.055461}, + {-0.107352, 0.120874, 0.137364, -0.030252}, + {-0.036897, 0.089972, 0.155831, -0.128475}, + {-0.059070, 0.097879, 0.084489, -0.075821}, + {-0.050865, -0.025167, -0.086636, 0.011256}, + {-0.051426, 0.013301, -0.144665, 0.038541}, + {-0.073831, -0.028917, -0.142416, -0.025268}, + {-0.083910, 0.015004, -0.227113, -0.002808}, + {-0.030840, -0.009326, -0.070517, -0.041304}, + {-0.022018, 0.029381, -0.124961, -0.031624}, + {-0.064222, -0.014640, -0.108798, -0.092342}, + {-0.038801, 0.038133, -0.188992, -0.094221}, + {-0.154059, -0.183932, -0.019894, 0.082105}, + {-0.188022, -0.113072, -0.117380, 0.090911}, + {-0.243301, -0.207086, -0.053735, -0.001975}, + {-0.275931, -0.121035, -0.161261, 0.004231}, + {-0.118142, -0.157537, -0.036594, -0.008679}, + {-0.153627, -0.111372, -0.103095, -0.009460}, + {-0.173458, -0.180158, -0.057130, -0.103198}, + {-0.208509, -0.127679, -0.149336, -0.109289}, + {0.096310, 0.047927, -0.024094, -0.057018}, + {0.044289, 0.075486, -0.008505, -0.067635}, + {0.076751, 0.025560, -0.066428, -0.102991}, + {0.025215, 0.090417, -0.058616, -0.114284}, + {0.125980, 0.070078, 0.016282, -0.112355}, + {0.070859, 0.118988, 0.001180, -0.116359}, + {0.097520, 0.059219, -0.026821, -0.172850}, + {0.048226, 0.145459, -0.050093, -0.188853}, + {0.007242, -0.135796, 0.147832, -0.034080}, + {0.012843, -0.069616, 0.077139, -0.047909}, + {-0.050911, -0.116323, 0.082521, -0.056362}, + {-0.039630, -0.055678, 0.036066, -0.067992}, + {0.042694, -0.091527, 0.150940, -0.124225}, + {0.029225, -0.039401, 0.071664, -0.113665}, + {-0.025085, -0.099013, 0.074622, -0.138674}, + {-0.031220, -0.035717, 0.020870, -0.143376}, + {0.040638, 0.087903, -0.049500, 0.094607}, + {0.026860, 0.125924, -0.103449, 0.140882}, + {0.075166, 0.110186, -0.115173, 0.067330}, + {0.036642, 0.163193, -0.188762, 0.103724}, + {0.028179, 0.095124, -0.053258, 0.028900}, + {0.002307, 0.148211, -0.096037, 0.046189}, + {0.072227, 0.137595, -0.095629, 0.001339}, + {0.033308, 0.221480, -0.152201, 0.012125}, + {0.003458, -0.085112, 0.041850, 0.113836}, + {-0.040610, -0.044880, 0.029732, 0.177011}, + {0.011404, -0.054324, -0.012426, 0.077815}, + {-0.042413, -0.030930, -0.034844, 0.122946}, + {-0.002206, -0.045698, 0.050651, 0.054886}, + {-0.041729, -0.016110, 0.048005, 0.102125}, + {0.013963, -0.022204, 0.001613, 0.028997}, + {-0.030218, -0.002052, -0.004365, 0.065343}, + {0.299049, 0.046260, 0.076320, 0.070784}, + {0.250160, 0.098440, 0.012590, 0.137479}, + {0.254170, 0.095310, 0.018749, 0.004288}, + {0.218892, 0.145554, -0.035161, 0.069784}, + {0.303486, 0.101424, 0.135996, -0.013096}, + {0.262919, 0.165133, 0.077237, 0.071721}, + {0.319358, 0.170283, 0.054554, -0.072210}, + {0.272983, 0.231181, -0.014471, 0.011689}, + {0.134116, -0.026693, 0.161400, 0.110292}, + {0.100379, 0.026517, 0.086236, 0.130478}, + {0.144718, -0.000895, 0.093767, 0.044514}, + {0.114943, 0.022145, 0.035871, 0.069193}, + {0.122051, 0.011043, 0.192803, 0.022796}, + {0.079482, 0.026156, 0.117725, 0.056565}, + {0.124641, 0.027387, 0.122956, -0.025369}, + {0.090708, 0.027357, 0.064450, 0.013058}, + {0.159781, -0.055202, -0.090597, 0.151598}, + {0.084577, -0.037203, -0.126698, 0.119739}, + {0.192484, -0.100195, -0.162066, 0.104148}, + {0.114579, -0.046270, -0.219547, 0.100067}, + {0.153083, -0.010127, -0.086266, 0.068648}, + {0.088202, -0.010515, -0.102196, 0.046281}, + {0.164494, -0.057325, -0.132860, 0.024093}, + {0.109419, -0.013999, -0.169596, 0.020412}, + {0.039180, -0.209168, -0.035872, 0.087949}, + {0.012790, -0.177723, -0.129986, 0.073364}, + {0.045261, -0.256694, -0.088186, 0.004212}, + {-0.005314, -0.231202, -0.191671, -0.002628}, + {0.037963, -0.153227, -0.045364, 0.003322}, + {0.030800, -0.126452, -0.114266, -0.010414}, + {0.044125, -0.184146, -0.081400, -0.077341}, + {0.029204, -0.157393, -0.172017, -0.089814}, + {0.393519, -0.043228, -0.111365, -0.000740}, + {0.289581, 0.018928, -0.123140, 0.000713}, + {0.311229, -0.059735, -0.198982, -0.081664}, + {0.258659, 0.052505, -0.211913, -0.034928}, + {0.300693, 0.011381, -0.083545, -0.086683}, + {0.214523, 0.053878, -0.101199, -0.061018}, + {0.253422, 0.028496, -0.156752, -0.163342}, + {0.199123, 0.113877, -0.166220, -0.102584}, + {0.249134, -0.165135, 0.028917, 0.051838}, + {0.156434, -0.123708, 0.017053, 0.043043}, + {0.214763, -0.101243, -0.005581, -0.020703}, + {0.140554, -0.072067, -0.015063, -0.011165}, + {0.241791, -0.152048, 0.106403, -0.046857}, + {0.142316, -0.131899, 0.054076, -0.026485}, + {0.206535, -0.086116, 0.046640, -0.097615}, + {0.129759, -0.081874, 0.004693, -0.073169} +}; + +/* + * Higher Order Coefficients + */ +const float AmbeHOCb5[32][4] = { + {0.264108, 0.045976, -0.200999, -0.122344}, + {0.479006, 0.227924, -0.016114, -0.006835}, + {0.077297, 0.080775, -0.068936, 0.041733}, + {0.185486, 0.231840, 0.182410, 0.101613}, + {-0.012442, 0.223718, -0.277803, -0.034370}, + {-0.059507, 0.139621, -0.024708, -0.104205}, + {-0.248676, 0.255502, -0.134894, -0.058338}, + {-0.055122, 0.427253, 0.025059, -0.045051}, + {-0.058898, -0.061945, 0.028030, -0.022242}, + {0.084153, 0.025327, 0.066780, -0.180839}, + {-0.193125, -0.082632, 0.140899, -0.089559}, + {0.000000, 0.033758, 0.276623, 0.002493}, + {-0.396582, -0.049543, -0.118100, -0.208305}, + {-0.287112, 0.096620, 0.049650, -0.079312}, + {-0.543760, 0.171107, -0.062173, -0.010483}, + {-0.353572, 0.227440, 0.230128, -0.032089}, + {0.248579, -0.279824, -0.209589, 0.070903}, + {0.377604, -0.119639, 0.008463, -0.005589}, + {0.102127, -0.093666, -0.061325, 0.052082}, + {0.154134, -0.105724, 0.099317, 0.187972}, + {-0.139232, -0.091146, -0.275479, -0.038435}, + {-0.144169, 0.034314, -0.030840, 0.022207}, + {-0.143985, 0.079414, -0.194701, 0.175312}, + {-0.195329, 0.087467, 0.067711, 0.186783}, + {-0.123515, -0.377873, -0.209929, -0.212677}, + {0.068698, -0.255933, 0.120463, -0.095629}, + {-0.106810, -0.319964, -0.089322, 0.106947}, + {-0.158605, -0.309606, 0.190900, 0.089340}, + {-0.489162, -0.432784, -0.151215, -0.005786}, + {-0.370883, -0.154342, -0.022545, 0.114054}, + {-0.742866, -0.204364, -0.123865, -0.038888}, + {-0.573077, -0.115287, 0.208879, -0.027698} +}; + +/* + * Higher Order Coefficients + */ +const float AmbeHOCb6[16][4] = { + {-0.143886, 0.235528, -0.116707, 0.025541}, + {-0.170182, -0.063822, -0.096934, 0.109704}, + {0.232915, 0.269793, 0.047064, -0.032761}, + {0.153458, 0.068130, -0.033513, 0.126553}, + {-0.440712, 0.132952, 0.081378, -0.013210}, + {-0.480433, -0.249687, -0.012280, 0.007112}, + {-0.088001, 0.167609, 0.148323, -0.119892}, + {-0.104628, 0.102639, 0.183560, 0.121674}, + {0.047408, -0.000908, -0.214196, -0.109372}, + {0.113418, -0.240340, -0.121420, 0.041117}, + {0.385609, 0.042913, -0.184584, -0.017851}, + {0.453830, -0.180745, 0.050455, 0.030984}, + {-0.155984, -0.144212, 0.018226, -0.146356}, + {-0.104028, -0.260377, 0.146472, 0.101389}, + {0.012376, -0.000267, 0.006657, -0.013941}, + {0.165852, -0.103467, 0.119713, -0.075455} +}; + +/* + * Higher Order Coefficients + */ +const float AmbeHOCb7[16][4] = { + {0.182478, 0.271794, -0.057639, 0.026115}, + {0.110795, 0.092854, 0.078125, -0.082726}, + {0.057964, 0.000833, 0.176048, 0.135404}, + {-0.027315, 0.098668, -0.065801, 0.116421}, + {-0.222796, 0.062967, 0.201740, -0.089975}, + {-0.193571, 0.309225, -0.014101, -0.034574}, + {-0.389053, -0.181476, 0.107682, 0.050169}, + {-0.345604, 0.064900, -0.065014, 0.065642}, + {0.319393, -0.055491, -0.220727, -0.067499}, + {0.460572, 0.084686, 0.048453, -0.011050}, + {0.201623, -0.068994, -0.067101, 0.108320}, + {0.227528, -0.173900, 0.092417, -0.066515}, + {-0.016927, 0.047757, -0.177686, -0.102163}, + {-0.052553, -0.065689, 0.019328, -0.033060}, + {-0.144910, -0.238617, -0.195206, -0.063917}, + {-0.024159, -0.338822, 0.003581, 0.060995} +}; + +/* + * Higher Order Coefficients + */ +const float AmbeHOCb8[8][4] = { + {0.323968, 0.008964, -0.063117, 0.027909}, + {0.010900, -0.004030, -0.125016, -0.080818}, + {0.109969, 0.256272, 0.042470, 0.000749}, + {-0.135446, 0.201769, -0.083426, 0.093888}, + {-0.441995, 0.038159, 0.022784, 0.003943}, + {-0.155951, 0.032467, 0.145309, -0.041725}, + {-0.149182, -0.223356, -0.065793, 0.075016}, + {0.096949, -0.096400, 0.083194, 0.049306} +}; + +#endif // __AMBE3600x2450_CONST_H__ diff --git a/vocoder/ecc.c b/vocoder/ecc.c new file mode 100644 index 0000000..cc296b0 --- /dev/null +++ b/vocoder/ecc.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - MBE Vocoder + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + */ + +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#define _USE_MATH_DEFINES +#include + +#include "ecc_const.h" + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +/* */ + +void mbe_checkGolayBlock(long int* block) +{ + static int i, syndrome, eccexpected, eccbits, databits; + long int mask, block_l; + + block_l = *block; + + mask = 0x400000l; + eccexpected = 0; + for (i = 0; i < 12; i++) { + if ((block_l & mask) != 0l) { + eccexpected ^= golayGenerator[i]; + } + + mask = mask >> 1; + } + + eccbits = (int)(block_l & 0x7ffl); + syndrome = eccexpected ^ eccbits; + + databits = (int)(block_l >> 11); + databits = databits ^ golayMatrix[syndrome]; + + *block = (long)databits; +} + +/* */ + +int mbe_golay2312(char* in, char* out) +{ + int i, errs; + long block; + + block = 0; + for (i = 22; i >= 0; i--) { + block = block << 1; + block = block + in[i]; + } + + mbe_checkGolayBlock(&block); + + for (i = 22; i >= 11; i--) { + out[i] = (block & 2048) >> 11; + block = block << 1; + } + + for (i = 10; i >= 0; i--) { + out[i] = in[i]; + } + + errs = 0; + for (i = 22; i >= 11; i--) { + if (out[i] != in[i]) { + errs++; + } + } + return (errs); +} + +/* */ + +int mbe_hamming1511(char* in, char* out) +{ + int i, j, errs, block, syndrome, stmp, stmp2; + + errs = 0; + + block = 0; + for (i = 14; i >= 0; i--) { + block <<= 1; + block |= in[i]; + } + + syndrome = 0; + for (i = 0; i < 4; i++) { + syndrome <<= 1; + stmp = block; + stmp &= hammingGenerator[i]; + + stmp2 = (stmp % 2); + for (j = 0; j < 14; j++) + { + stmp >>= 1; + stmp2 ^= (stmp % 2); + } + + syndrome |= stmp2; + } + + if (syndrome > 0) { + errs++; + block ^= hammingMatrix[syndrome]; + } + + for (i = 14; i >= 0; i--) { + out[i] = (block & 0x4000) >> 14; + block = block << 1; + } + return (errs); +} + +/* */ + +int mbe_7100x4400Hamming1511(char* in, char* out) +{ + int i, j, errs, block, syndrome, stmp, stmp2; + + errs = 0; + + block = 0; + for (i = 14; i >= 0; i--) { + block <<= 1; + block |= in[i]; + } + + syndrome = 0; + for (i = 0; i < 4; i++) { + syndrome <<= 1; + stmp = block; + stmp &= imbe7100x4400hammingGenerator[i]; + + stmp2 = (stmp % 2); + for (j = 0; j < 14; j++) + { + stmp >>= 1; + stmp2 ^= (stmp % 2); + } + + syndrome |= stmp2; + } + + if (syndrome > 0) { + errs++; + block ^= hammingMatrix[syndrome]; + } + + for (i = 14; i >= 0; i--) { + out[i] = (block & 0x4000) >> 14; + block = block << 1; + } + + return (errs); +} diff --git a/vocoder/ecc_const.h b/vocoder/ecc_const.h new file mode 100644 index 0000000..b8642b7 --- /dev/null +++ b/vocoder/ecc_const.h @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - MBE Vocoder + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + */ +/** + * @file ecc_const.h + * @ingroup vocoder + */ + +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#if !defined(__ECC_CONST_H__) +#define __ECC_CONST_H__ + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +const int hammingGenerator[4] = { + 0x7f08, 0x78e4, 0x66d2, 0x55b1 +}; + +const int imbe7100x4400hammingGenerator[4] = { + 0x7ac8, 0x3d64, 0x1eb2, 0x7591 +}; + +const int hammingMatrix[16] = { + 0x0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000 +}; + +const int golayGenerator[12] = { + 0x63a, 0x31d, 0x7b4, 0x3da, 0x1ed, 0x6cc, 0x366, 0x1b3, 0x6e3, 0x54b, 0x49f, 0x475 +}; + +const int golayMatrix[2048] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 2084, 0, 0, 0, 769, 0, 1024, 144, + 2, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 72, 0, 72, 72, 72, 0, 0, 0, 16, 0, 1, 1538, 384, 0, 134, 2048, 1056, 288, + 2576, 5, 72, 0, 0, 0, 0, 0, 0, 0, 1280, 0, 0, 0, 4, 0, 546, 144, 2049, 0, 0, 0, 66, 0, 1, 144, 520, 0, 2056, 144, + 1056, 144, 324, 144, 144, 0, 0, 0, 2688, 0, 1, 32, 22, 0, 272, 3, 1056, 3076, 128, 768, 72, 0, 1, 268, 1056, 1, 1, 2112, 1, 576, + 1056, 1056, 1056, 10, 1, 144, 1056, 0, 0, 0, 0, 0, 0, 0, 1280, 0, 0, 0, 160, 0, 21, 2560, 2, 0, 0, 0, 16, 0, 704, 9, + 2, 0, 2056, 1092, 2, 288, 2, 2, 2, 0, 0, 0, 16, 0, 2050, 132, 545, 0, 1536, 3, 2308, 288, 128, 1040, 72, 0, 16, 16, 16, 288, + 1036, 2112, 16, 288, 65, 648, 16, 288, 288, 288, 2, 0, 0, 0, 1280, 0, 1280, 1280, 1280, 0, 2056, 3, 592, 64, 128, 44, 1280, 0, 2056, 544, + 133, 6, 48, 2112, 1280, 2056, 2056, 256, 2056, 1537, 2056, 144, 2, 0, 100, 3, 8, 536, 128, 2112, 1280, 3, 128, 3, 3, 128, 128, 3, 128, 1152, + 770, 2112, 16, 2112, 1, 2112, 2112, 20, 2056, 3, 1056, 288, 128, 2112, 516, 0, 0, 0, 0, 0, 0, 0, 131, 0, 0, 0, 4, 0, 1024, 2560, + 304, 0, 0, 0, 16, 0, 1024, 320, 520, 0, 1024, 42, 2240, 1024, 1024, 5, 1024, 0, 0, 0, 16, 0, 772, 32, 3072, 0, 2081, 1408, 514, 18, + 128, 5, 72, 0, 16, 16, 16, 2184, 98, 5, 16, 576, 264, 5, 16, 5, 1024, 5, 5, 0, 0, 0, 4, 0, 2128, 32, 520, 0, 4, 4, + 4, 265, 128, 1090, 4, 0, 416, 3073, 520, 6, 520, 520, 520, 576, 19, 256, 4, 2080, 1024, 144, 520, 0, 1034, 32, 321, 32, 128, 32, 32, 576, + 128, 2072, 4, 128, 128, 32, 128, 576, 2052, 130, 16, 1296, 1, 32, 520, 576, 576, 576, 1056, 576, 128, 5, 2306, 0, 0, 0, 16, 0, 40, 2560, + 68, 0, 322, 2560, 1033, 2560, 128, 2560, 2560, 0, 16, 16, 16, 6, 2305, 1184, 16, 129, 548, 256, 16, 88, 1024, 2560, 2, 0, 16, 16, 16, 1089, + 128, 266, 16, 12, 128, 96, 16, 128, 128, 2560, 128, 16, 16, 16, 16, 512, 16, 16, 16, 3074, 16, 16, 16, 288, 128, 5, 16, 0, 513, 200, + 2082, 6, 128, 17, 1280, 1072, 128, 256, 4, 128, 128, 2560, 128, 6, 1088, 256, 16, 6, 6, 6, 520, 256, 2056, 256, 256, 6, 128, 256, 97, 2304, + 128, 1540, 16, 128, 128, 32, 128, 128, 128, 3, 128, 128, 128, 128, 128, 41, 16, 16, 16, 6, 128, 2112, 16, 576, 128, 256, 16, 128, 128, 1032, + 128, 0, 0, 0, 0, 0, 0, 0, 528, 0, 0, 0, 160, 0, 1024, 262, 2049, 0, 0, 0, 66, 0, 1024, 9, 384, 0, 1024, 2048, 28, 1024, + 1024, 608, 1024, 0, 0, 0, 1029, 0, 2050, 32, 384, 0, 272, 2048, 514, 641, 36, 1040, 72, 0, 552, 2048, 384, 84, 384, 384, 384, 2048, 65, 2048, + 2048, 10, 1024, 2048, 384, 0, 0, 0, 66, 0, 140, 32, 2049, 0, 272, 1544, 2049, 64, 2049, 2049, 2049, 0, 66, 66, 66, 2816, 48, 1028, 66, 37, + 640, 256, 66, 10, 1024, 144, 2049, 0, 272, 32, 8, 32, 1600, 32, 32, 272, 272, 196, 272, 10, 272, 32, 2049, 1152, 2052, 529, 66, 10, 1, 32, + 384, 10, 272, 2048, 1056, 10, 10, 10, 516, 0, 0, 0, 160, 0, 2050, 9, 68, 0, 160, 160, 160, 64, 776, 1040, 160, 0, 260, 9, 3584, 9, + 48, 9, 9, 530, 65, 256, 160, 2180, 1024, 9, 2, 0, 2050, 832, 8, 2050, 2050, 1040, 2050, 12, 65, 1040, 160, 1040, 2050, 1040, 1040, 1152, 65, 38, + 16, 512, 2050, 9, 384, 65, 65, 2048, 65, 288, 65, 1040, 516, 0, 513, 2068, 8, 64, 48, 642, 1280, 64, 1030, 256, 160, 64, 64, 64, 2049, 1152, + 48, 256, 66, 48, 48, 9, 48, 256, 2056, 256, 256, 64, 48, 256, 516, 1152, 8, 8, 8, 261, 2050, 32, 8, 2592, 272, 3, 8, 64, 128, 1040, + 516, 1152, 1152, 1152, 8, 1152, 48, 2112, 516, 1152, 65, 256, 516, 10, 516, 516, 516, 0, 0, 0, 2312, 0, 1024, 32, 68, 0, 1024, 81, 514, 1024, + 1024, 136, 1024, 0, 1024, 644, 33, 1024, 1024, 2066, 1024, 1024, 1024, 256, 1024, 1024, 1024, 1024, 1024, 0, 192, 32, 514, 32, 25, 32, 32, 12, 514, 514, + 514, 2368, 1024, 32, 514, 259, 2052, 1096, 16, 512, 1024, 32, 384, 176, 1024, 2048, 514, 1024, 1024, 5, 1024, 0, 513, 32, 1168, 32, 258, 32, 32, 2178, + 104, 256, 4, 532, 1024, 32, 2049, 24, 2052, 256, 66, 193, 1024, 32, 520, 256, 1024, 256, 256, 1024, 1024, 256, 1024, 32, 2052, 32, 32, 32, 32, 32, + 32, 1025, 272, 32, 514, 32, 128, 32, 32, 2052, 2052, 32, 2052, 32, 2052, 32, 32, 576, 2052, 256, 137, 10, 1024, 32, 80, 0, 513, 1026, 68, 400, + 68, 68, 68, 12, 2064, 256, 160, 35, 1024, 2560, 68, 2144, 138, 256, 16, 512, 1024, 9, 68, 256, 1024, 256, 256, 1024, 1024, 256, 1024, 12, 1312, 2177, + 16, 512, 2050, 32, 68, 12, 12, 12, 514, 12, 128, 1040, 257, 512, 16, 16, 16, 512, 512, 512, 16, 12, 65, 256, 16, 512, 1024, 194, 2088, 513, + 513, 256, 513, 3080, 513, 32, 68, 256, 513, 256, 256, 64, 128, 256, 26, 256, 513, 256, 256, 6, 48, 256, 2176, 256, 256, 256, 256, 256, 1024, 256, + 256, 82, 513, 32, 8, 32, 128, 32, 32, 12, 128, 256, 3136, 128, 128, 32, 128, 1152, 2052, 256, 16, 512, 328, 32, 1027, 256, 34, 256, 256, 2065, + 128, 256, 516, 0, 0, 0, 0, 0, 0, 0, 528, 0, 0, 0, 4, 0, 2432, 1057, 2, 0, 0, 0, 1160, 0, 1, 320, 2, 0, 112, 2048, + 2, 524, 2, 2, 2, 0, 0, 0, 290, 0, 1, 132, 3072, 0, 1536, 2048, 145, 18, 36, 768, 72, 0, 1, 2048, 580, 1, 1, 56, 1, 2048, + 264, 2048, 2048, 1216, 1, 2048, 2, 0, 0, 0, 4, 0, 1, 2058, 224, 0, 4, 4, 4, 64, 1048, 768, 4, 0, 1, 544, 2320, 1, 1, 1028, + 1, 1282, 640, 73, 4, 2080, 1, 144, 2, 0, 1, 1104, 8, 1, 1, 768, 1, 168, 2114, 768, 4, 768, 1, 768, 768, 1, 1, 130, 1, 1, + 1, 1, 1, 20, 1, 2048, 1056, 1, 1, 768, 1, 0, 0, 0, 2113, 0, 40, 132, 2, 0, 1536, 280, 2, 64, 2, 2, 2, 0, 260, 544, + 2, 3088, 2, 2, 2, 129, 2, 2, 2, 2, 2, 2, 2, 0, 1536, 132, 8, 132, 336, 132, 132, 1536, 1536, 96, 1536, 2057, 1536, 132, 2, 74, + 2208, 1281, 16, 512, 1, 132, 2, 20, 1536, 2048, 2, 288, 2, 2, 2, 0, 146, 544, 8, 64, 2564, 17, 1280, 64, 289, 3200, 4, 64, 64, 64, + 2, 544, 1088, 544, 544, 392, 1, 544, 2, 20, 2056, 544, 2, 64, 2, 2, 2, 2304, 8, 8, 8, 1058, 1, 132, 8, 20, 1536, 3, 8, 64, + 128, 768, 2096, 20, 1, 544, 8, 1, 1, 2112, 1, 20, 20, 20, 448, 20, 1, 1032, 2, 0, 0, 0, 4, 0, 40, 320, 3072, 0, 4, 4, + 4, 18, 577, 136, 4, 0, 2562, 320, 33, 320, 148, 320, 320, 129, 264, 1552, 4, 2080, 1024, 320, 2, 0, 192, 521, 3072, 18, 3072, 3072, 3072, 18, + 264, 96, 4, 18, 18, 18, 3072, 1060, 264, 130, 16, 512, 1, 320, 3072, 264, 264, 2048, 264, 18, 264, 5, 672, 0, 4, 4, 4, 1664, 258, 17, + 4, 4, 4, 4, 4, 2080, 4, 4, 4, 24, 1088, 130, 4, 2080, 1, 320, 520, 2080, 4, 4, 4, 2080, 2080, 2080, 4, 2304, 560, 130, 4, 76, + 1, 32, 3072, 1025, 4, 4, 4, 18, 128, 768, 4, 130, 1, 130, 130, 1, 1, 130, 1, 576, 264, 130, 4, 2080, 1, 1032, 80, 0, 40, 1026, + 896, 40, 40, 17, 40, 129, 2064, 96, 4, 1284, 40, 2560, 2, 129, 1088, 2060, 16, 512, 40, 320, 2, 129, 129, 129, 2, 129, 2, 2, 2, 2304, + 7, 96, 16, 512, 40, 132, 3072, 96, 1536, 96, 96, 18, 128, 96, 257, 512, 16, 16, 16, 512, 512, 512, 16, 129, 264, 96, 16, 512, 2116, 1032, + 2, 2304, 1088, 17, 4, 17, 40, 17, 17, 522, 4, 4, 4, 64, 128, 17, 4, 1088, 1088, 544, 1088, 6, 1088, 17, 2176, 129, 1088, 256, 4, 2080, + 784, 1032, 2, 2304, 2304, 2304, 8, 2304, 128, 17, 578, 2304, 128, 96, 4, 128, 128, 1032, 128, 2304, 1088, 130, 16, 512, 1, 1032, 292, 20, 34, 1032, + 2561, 1032, 128, 1032, 1032, 0, 0, 0, 528, 0, 528, 528, 528, 0, 11, 2048, 1344, 64, 36, 136, 528, 0, 260, 2048, 33, 162, 2120, 1028, 528, 2048, + 640, 2048, 2048, 273, 1024, 2048, 2, 0, 192, 2048, 8, 1288, 36, 67, 528, 2048, 36, 2048, 2048, 36, 36, 2048, 36, 2048, 1042, 2048, 2048, 512, 1, 2048, + 384, 2048, 2048, 2048, 2048, 2048, 36, 2048, 2048, 0, 3104, 385, 8, 64, 258, 1028, 528, 64, 640, 50, 4, 64, 64, 64, 2049, 24, 640, 1028, 66, 1028, + 1, 1028, 1028, 640, 640, 2048, 640, 64, 640, 1028, 296, 518, 8, 8, 8, 2192, 1, 32, 8, 1025, 272, 2048, 8, 64, 36, 768, 1154, 352, 1, 2048, + 8, 1, 1, 1028, 1, 2048, 640, 2048, 2048, 10, 1, 2048, 80, 0, 260, 1026, 8, 64, 1153, 2336, 528, 64, 2064, 517, 160, 64, 64, 64, 2, 260, + 260, 208, 260, 512, 260, 9, 2, 1064, 260, 2048, 2, 64, 2, 2, 2, 49, 8, 8, 8, 512, 2050, 132, 8, 386, 1536, 2048, 8, 64, 36, 1040, + 257, 512, 260, 2048, 8, 512, 512, 512, 1120, 2048, 65, 2048, 2048, 512, 152, 2048, 2, 64, 8, 8, 8, 64, 64, 64, 8, 64, 64, 64, 8, 64, + 64, 64, 64, 2051, 260, 544, 8, 64, 48, 1028, 2176, 64, 640, 256, 1041, 64, 64, 64, 2, 8, 8, 8, 8, 64, 8, 8, 8, 64, 8, 8, + 8, 64, 64, 64, 8, 1152, 8, 8, 8, 512, 1, 274, 8, 20, 34, 2048, 8, 64, 3328, 161, 516, 0, 192, 1026, 33, 2053, 258, 136, 528, 800, + 2064, 136, 4, 136, 1024, 136, 136, 24, 33, 33, 33, 512, 1024, 320, 33, 70, 1024, 2048, 33, 1024, 1024, 136, 1024, 192, 192, 276, 192, 512, 192, 32, + 3072, 1025, 192, 2048, 514, 18, 36, 136, 257, 512, 192, 2048, 33, 512, 512, 512, 14, 2048, 264, 2048, 2048, 512, 1024, 2048, 80, 24, 258, 2624, 4, 258, + 258, 32, 258, 1025, 4, 4, 4, 64, 258, 136, 4, 24, 24, 24, 33, 24, 258, 1028, 2176, 24, 640, 256, 4, 2080, 1024, 515, 80, 1025, 192, 32, + 8, 32, 258, 32, 32, 1025, 1025, 1025, 4, 1025, 2568, 32, 80, 24, 2052, 130, 1792, 512, 1, 32, 80, 1025, 34, 2048, 80, 388, 80, 80, 80, 1026, + 2064, 1026, 1026, 512, 40, 1026, 68, 2064, 2064, 1026, 2064, 64, 2064, 136, 257, 512, 260, 1026, 33, 512, 512, 512, 2176, 129, 2064, 256, 584, 512, 1024, 52, + 2, 512, 192, 1026, 8, 512, 512, 512, 257, 12, 2064, 96, 257, 512, 257, 257, 257, 512, 512, 512, 16, 512, 512, 512, 512, 512, 34, 2048, 1156, 512, + 512, 512, 257, 164, 513, 1026, 8, 64, 258, 17, 2176, 64, 2064, 256, 4, 64, 64, 64, 1568, 24, 1088, 256, 2176, 512, 2176, 2176, 2176, 256, 34, 256, + 256, 64, 13, 256, 2176, 2304, 8, 8, 8, 512, 1044, 32, 8, 1025, 34, 656, 8, 64, 128, 2054, 257, 512, 34, 69, 8, 512, 512, 512, 2176, 34, + 34, 256, 34, 512, 34, 1032, 80 +}; + +#endif // __ECC_CONST_H__ diff --git a/vocoder/imbe/aux_sub.cpp b/vocoder/imbe/aux_sub.cpp new file mode 100644 index 0000000..9c4dec7 --- /dev/null +++ b/vocoder/imbe/aux_sub.cpp @@ -0,0 +1,183 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/basic_op.h" +#include "imbe/imbe.h" +#include "imbe/aux_sub.h" +#include "imbe/tbls.h" + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// PURPOSE: +// Return pointer to bit allocation array +// according to the number of harmonics +// +// INPUT: +// num_harms - The number of harmonics +// +// OUTPUT: +// None +// +// RETURN: +// Pointer to bits allocation array +// +//----------------------------------------------------------------------------- +const UWord16* get_bit_allocation_arr(Word16 num_harms) +{ + Word16 offset_in_word, index; + + if (num_harms == NUM_HARMS_MIN) + return &bit_allocation_tbl[0]; + else { + index = num_harms - NUM_HARMS_MIN - 1; + offset_in_word = bit_allocation_offset_tbl[index >> 2] + ((3 + (index >> 2)) * (index & 0x3)); + return &bit_allocation_tbl[offset_in_word]; + } +} + +//----------------------------------------------------------------------------- +// PURPOSE: +// Unpack bit allocation table's item +// +// INPUT: +// num_harms - The number of harmonics +// ptr - Pointer to buffer to place bit allocation data +// +// OUTPUT: +// Unpacked bit allocation table +// +// RETURN: +// None +// +//----------------------------------------------------------------------------- +void get_bit_allocation(Word16 num_harms, Word16* ptr) +{ + const UWord16* bat_ptr; + Word16 i, tmp; + + bat_ptr = get_bit_allocation_arr(num_harms); + + for (i = 0; i < num_harms - 1; i += 4) { + tmp = *bat_ptr++; + ptr[3] = tmp & 0xF; tmp >>= 4; + ptr[2] = tmp & 0xF; tmp >>= 4; + ptr[1] = tmp & 0xF; tmp >>= 4; + ptr[0] = tmp & 0xF; + ptr += 4; + } +} + +//----------------------------------------------------------------------------- +// PURPOSE: +// Set the elements of a 16 bit input vector to zero. +// +// INPUT: +// vec - Pointer to vector +// n - size of vec +// +// OUTPUT: +// None +// +// RETURN: +// None +// +//----------------------------------------------------------------------------- +void v_zap(Word16* vec, Word16 n) +{ + while (n--) + *vec++ = 0; +} + +//----------------------------------------------------------------------------- +// PURPOSE: +// Copy the contents of one 16 bit input vector to another +// +// INPUT: +// vec1 - Pointer to the destination vector +// vec2 - Pointer to the source vector +// n - size of data should be copied +// +// OUTPUT: +// Copy of the source vector +// +// RETURN: +// None +// +//----------------------------------------------------------------------------- +void v_equ(Word16* vec1, Word16* vec2, Word16 n) +{ + while (n--) + *vec1++ = *vec2++; +} + +//----------------------------------------------------------------------------- +// PURPOSE: +// Compute the sum of square magnitude of a 16 bit input vector +// with saturation and truncation. Output is a 32 bit number. +// +// INPUT: +// vec - Pointer to the vector +// n - size of input vectors +// +// OUTPUT: +// none +// +// RETURN: +// 32 bit long signed integer result +// +//----------------------------------------------------------------------------- +Word32 L_v_magsq(Word16* vec, Word16 n) +{ + Word32 L_magsq = 0; + + while (n--) { + L_magsq = L_mac(L_magsq, *vec, *vec); + vec++; + } + return L_magsq; +} + +//----------------------------------------------------------------------------- +// PURPOSE: +// Copy the contents of one 16 bit input vector to another with shift +// +// INPUT: +// vec1 - Pointer to the destination vector +// vec2 - Pointer to the source vector +// scale - right shift factor +// n - size of data should be copied +// +// OUTPUT: +// Copy of the source vector +// +// RETURN: +// None +// +//----------------------------------------------------------------------------- +void v_equ_shr(Word16* vec1, Word16* vec2, Word16 scale, Word16 n) +{ + while (n--) + *vec1++ = shr(*vec2++, scale); +} diff --git a/vocoder/imbe/aux_sub.h b/vocoder/imbe/aux_sub.h new file mode 100644 index 0000000..815e14f --- /dev/null +++ b/vocoder/imbe/aux_sub.h @@ -0,0 +1,134 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ +#ifndef __AUX_SUB_H__ +#define __AUX_SUB_H__ + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// PURPOSE: +// Return pointer to bit allocation array +// according to the number of harmonics +// +// INPUT: +// num_harms - The number of harmonics +// +// OUTPUT: +// None +// +// RETURN: +// Pointer to bits allocation array +// +//----------------------------------------------------------------------------- +const UWord16 *get_bit_allocation_arr(Word16 num_harms); + +//----------------------------------------------------------------------------- +// PURPOSE: +// Unpack bit allocation table's item +// +// INPUT: +// num_harms - The number of harmonics +// ptr - Pointer to buffer to place bit allocation data +// +// OUTPUT: +// Unpacked bit allocation table +// +// RETURN: +// None +// +//----------------------------------------------------------------------------- +void get_bit_allocation(Word16 num_harms, Word16 *ptr); + +//----------------------------------------------------------------------------- +// PURPOSE: +// Set the elements of a 16 bit input vector to zero. +// +// INPUT: +// vec - Pointer to vector +// n - size of vec +// +// OUTPUT: +// None +// +// RETURN: +// None +// +//----------------------------------------------------------------------------- +void v_zap(Word16 *vec, Word16 n); + +//----------------------------------------------------------------------------- +// PURPOSE: +// Copy the contents of one 16 bit input vector to another +// +// INPUT: +// vec1 - Pointer to the destination vector +// vec2 - Pointer to the source vector +// n - size of data should be copied +// +// OUTPUT: +// Copy of the source vector +// +// RETURN: +// None +// +//----------------------------------------------------------------------------- +void v_equ(Word16 *vec1, Word16 *vec2, Word16 n); + +//----------------------------------------------------------------------------- +// PURPOSE: +// Compute the sum of square magnitude of a 16 bit input vector +// with saturation and truncation. Output is a 32 bit number. +// +// INPUT: +// vec - Pointer to the vector +// n - size of input vectors +// +// OUTPUT: +// none +// +// RETURN: +// 32 bit long signed integer result +// +//----------------------------------------------------------------------------- +Word32 L_v_magsq(Word16 *vec, Word16 n); + +//----------------------------------------------------------------------------- +// PURPOSE: +// Copy the contents of one 16 bit input vector to another with shift +// +// INPUT: +// vec1 - Pointer to the destination vector +// vec2 - Pointer to the source vector +// scale - right shift factor +// n - size of data should be copied +// +// OUTPUT: +// Copy of the source vector +// +// RETURN: +// None +// +//----------------------------------------------------------------------------- +void v_equ_shr(Word16 *vec1, Word16 *vec2, Word16 scale, Word16 n); + +#endif // __AUX_SUB_H__ diff --git a/vocoder/imbe/basic_op.cpp b/vocoder/imbe/basic_op.cpp new file mode 100644 index 0000000..6a24675 --- /dev/null +++ b/vocoder/imbe/basic_op.cpp @@ -0,0 +1,2008 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include +#include + +#include "imbe/typedef.h" +#include "imbe/basic_op.h" + +#if (WMOPS) +#include "count.h" +extern BASIC_OP multiCounter[MAXCOUNTERS]; +extern int currCounter; +#endif + +// --------------------------------------------------------------------------- +// Local Functions +// --------------------------------------------------------------------------- +Word16 saturate(Word32 L_var1); + +// --------------------------------------------------------------------------- +// Globals +// --------------------------------------------------------------------------- +Flag Overflow = 0; +Flag Carry = 0; + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +/*___________________________________________________________________________ + | | + | Function Name : saturate | + | | + | Purpose : | + | | + | Limit the 32 bit input to the range of a 16 bit word. | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +Word16 saturate(Word32 L_var1) +{ + Word16 var_out; + + if (L_var1 > 0X00007fffL) { + Overflow = 1; + var_out = MAX_16; + } + else if (L_var1 < (Word32)0xffff8000L) { + Overflow = 1; + var_out = MIN_16; + } + else { + var_out = extract_l(L_var1); +#if (WMOPS) + multiCounter[currCounter].extract_l--; +#endif + } + + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : add | + | | + | Purpose : | + | | + | Performs the addition (var1+var2) with overflow control and saturation;| + | the 16 bit result is set at +32767 when overflow occurs or at -32768 | + | when underflow occurs. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +Word16 add(Word16 var1, Word16 var2) +{ + Word16 var_out; + Word32 L_sum; + + L_sum = (Word32)var1 + var2; + var_out = saturate(L_sum); +#if (WMOPS) + multiCounter[currCounter].add++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : sub | + | | + | Purpose : | + | | + | Performs the subtraction (var1+var2) with overflow control and satu- | + | ration; the 16 bit result is set at +32767 when overflow occurs or at | + | -32768 when underflow occurs. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +Word16 sub(Word16 var1, Word16 var2) +{ + Word16 var_out; + Word32 L_diff; + + L_diff = (Word32)var1 - var2; + var_out = saturate(L_diff); +#if (WMOPS) + multiCounter[currCounter].sub++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : abs_s | + | | + | Purpose : | + | | + | Absolute value of var1; abs_s(-32768) = 32767. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 0000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +Word16 abs_s(Word16 var1) +{ + Word16 var_out; + + if (var1 == (Word16)0X8000) { + var_out = MAX_16; + } + else { + if (var1 < 0) { + var_out = -var1; + } + else { + var_out = var1; + } + } +#if (WMOPS) + multiCounter[currCounter].abs_s++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : shl | + | | + | Purpose : | + | | + | Arithmetically shift the 16 bit input var1 left var2 positions.Zero fill| + | the var2 LSB of the result. If var2 is negative, arithmetically shift | + | var1 right by -var2 with sign extension. Saturate the result in case of | + | underflows or overflows. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +Word16 shl(Word16 var1, Word16 var2) +{ + Word16 var_out; + Word32 result; + + if (var2 < 0) { + if (var2 < -16) + var2 = -16; + var_out = shr(var1, -var2); +#if (WMOPS) + multiCounter[currCounter].shr--; +#endif + } + else { + result = (Word32)var1 * ((Word32)1 << var2); + + if ((var2 > 15 && var1 != 0) || (result != (Word32)((Word16)result))) { + Overflow = 1; + var_out = (var1 > 0) ? MAX_16 : MIN_16; + } + else { + var_out = extract_l(result); +#if (WMOPS) + multiCounter[currCounter].extract_l--; +#endif + } + } +#if (WMOPS) + multiCounter[currCounter].shl++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : shr | + | | + | Purpose : | + | | + | Arithmetically shift the 16 bit input var1 right var2 positions with | + | sign extension. If var2 is negative, arithmetically shift var1 left by | + | -var2 with sign extension. Saturate the result in case of underflows or | + | overflows. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +Word16 shr(Word16 var1, Word16 var2) +{ + Word16 var_out; + + if (var2 < 0) { + if (var2 < -16) + var2 = -16; + var_out = shl(var1, -var2); +#if (WMOPS) + multiCounter[currCounter].shl--; +#endif + } + else { + if (var2 >= 15) { + var_out = (var1 < 0) ? -1 : 0; + } + else { + if (var1 < 0) { + var_out = ~((~var1) >> var2); + } + else { + var_out = var1 >> var2; + } + } + } + +#if (WMOPS) + multiCounter[currCounter].shr++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : mult | + | | + | Purpose : | + | | + | Performs the multiplication of var1 by var2 and gives a 16 bit result | + | which is scaled i.e.: | + | mult(var1,var2) = extract_l(L_shr((var1 times var2),15)) and | + | mult(-32768,-32768) = 32767. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +Word16 mult(Word16 var1, Word16 var2) +{ + Word16 var_out; + Word32 L_product; + + L_product = (Word32)var1 * (Word32)var2; + + L_product = (L_product & (Word32)0xffff8000L) >> 15; + + if (L_product & (Word32)0x00010000L) + L_product = L_product | (Word32)0xffff0000L; + + var_out = saturate(L_product); +#if (WMOPS) + multiCounter[currCounter].mult++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_mult | + | | + | Purpose : | + | | + | L_mult is the 32 bit result of the multiplication of var1 times var2 | + | with one shift left i.e.: | + | L_mult(var1,var2) = L_shl((var1 times var2),1) and | + | L_mult(-32768,-32768) = 2147483647. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ +Word32 L_mult(Word16 var1, Word16 var2) +{ + Word32 L_var_out; + + L_var_out = (Word32)var1 * (Word32)var2; + + if (L_var_out != (Word32)0x40000000L) { + L_var_out *= 2; + } + else { + Overflow = 1; + L_var_out = MAX_32; + } + +#if (WMOPS) + multiCounter[currCounter].L_mult++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : negate | + | | + | Purpose : | + | | + | Negate var1 with saturation, saturate in the case where input is -32768:| + | negate(var1) = sub(0,var1). | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +Word16 negate(Word16 var1) +{ + Word16 var_out; + + var_out = (var1 == MIN_16) ? MAX_16 : -var1; +#if (WMOPS) + multiCounter[currCounter].negate++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : extract_h | + | | + | Purpose : | + | | + | Return the 16 MSB of L_var1. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32 ) whose value falls in the | + | range : 0x8000 0000 <= L_var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +Word16 extract_h(Word32 L_var1) +{ + Word16 var_out; + + var_out = (Word16)(L_var1 >> 16); +#if (WMOPS) + multiCounter[currCounter].extract_h++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : extract_l | + | | + | Purpose : | + | | + | Return the 16 LSB of L_var1. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32 ) whose value falls in the | + | range : 0x8000 0000 <= L_var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +Word16 extract_l(Word32 L_var1) +{ + Word16 var_out; + + var_out = (Word16)L_var1; +#if (WMOPS) + multiCounter[currCounter].extract_l++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : round | + | | + | Purpose : | + | | + | Round the lower 16 bits of the 32 bit input number into the MS 16 bits | + | with saturation. Shift the resulting bits right by 16 and return the 16 | + | bit number: | + | L_round(L_var1) = extract_h(L_add(L_var1,32768)) | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32 ) whose value falls in the | + | range : 0x8000 0000 <= L_var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +Word16 L_round(Word32 L_var1) +{ + Word16 var_out; + Word32 L_rounded; + + L_rounded = L_add(L_var1, (Word32)0x00008000L); +#if (WMOPS) + multiCounter[currCounter].L_add--; +#endif + var_out = extract_h(L_rounded); +#if (WMOPS) + multiCounter[currCounter].extract_h--; + multiCounter[currCounter].round++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_mac | + | | + | Purpose : | + | | + | Multiply var1 by var2 and shift the result left by 1. Add the 32 bit | + | result to L_var3 with saturation, return a 32 bit result: | + | L_mac(L_var3,var1,var2) = L_add(L_var3,L_mult(var1,var2)). | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var3 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ +Word32 L_mac(Word32 L_var3, Word16 var1, Word16 var2) +{ + Word32 L_var_out; + Word32 L_product; + + L_product = L_mult(var1, var2); +#if (WMOPS) + multiCounter[currCounter].L_mult--; +#endif + L_var_out = L_add(L_var3, L_product); +#if (WMOPS) + multiCounter[currCounter].L_add--; + multiCounter[currCounter].L_mac++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_msu | + | | + | Purpose : | + | | + | Multiply var1 by var2 and shift the result left by 1. Subtract the 32 | + | bit result to L_var3 with saturation, return a 32 bit result: | + | L_msu(L_var3,var1,var2) = L_sub(L_var3,L_mult(var1,var2)). | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var3 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ +Word32 L_msu(Word32 L_var3, Word16 var1, Word16 var2) +{ + Word32 L_var_out; + Word32 L_product; + + L_product = L_mult(var1, var2); +#if (WMOPS) + multiCounter[currCounter].L_mult--; +#endif + L_var_out = L_sub(L_var3, L_product); +#if (WMOPS) + multiCounter[currCounter].L_sub--; + multiCounter[currCounter].L_msu++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_macNs | + | | + | Purpose : | + | | + | Multiply var1 by var2 and shift the result left by 1. Add the 32 bit | + | result to L_var3 without saturation, return a 32 bit result. Generate | + | carry and overflow values : | + | L_macNs(L_var3,var1,var2) = L_add_c(L_var3,L_mult(var1,var2)). | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var3 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + | | + | Caution : | + | | + | In some cases the Carry flag has to be cleared or set before using | + | operators which take into account its value. | + |___________________________________________________________________________| +*/ +Word32 L_macNs(Word32 L_var3, Word16 var1, Word16 var2) +{ + Word32 L_var_out; + + L_var_out = L_mult(var1, var2); +#if (WMOPS) + multiCounter[currCounter].L_mult--; +#endif + L_var_out = L_add_c(L_var3, L_var_out); +#if (WMOPS) + multiCounter[currCounter].L_add_c--; + multiCounter[currCounter].L_macNs++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_msuNs | + | | + | Purpose : | + | | + | Multiply var1 by var2 and shift the result left by 1. Subtract the 32 | + | bit result from L_var3 without saturation, return a 32 bit result. Ge- | + | nerate carry and overflow values : | + | L_msuNs(L_var3,var1,var2) = L_sub_c(L_var3,L_mult(var1,var2)). | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var3 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + | | + | Caution : | + | | + | In some cases the Carry flag has to be cleared or set before using | + | operators which take into account its value. | + |___________________________________________________________________________| +*/ +Word32 L_msuNs(Word32 L_var3, Word16 var1, Word16 var2) +{ + Word32 L_var_out; + + L_var_out = L_mult(var1, var2); +#if (WMOPS) + multiCounter[currCounter].L_mult--; +#endif + L_var_out = L_sub_c(L_var3, L_var_out); +#if (WMOPS) + multiCounter[currCounter].L_sub_c--; + multiCounter[currCounter].L_msuNs++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_add | + | | + | Purpose : | + | | + | 32 bits addition of the two 32 bits variables (L_var1+L_var2) with | + | overflow control and saturation; the result is set at +2147483647 when | + | overflow occurs or at -2147483648 when underflow occurs. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | L_var2 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ +Word32 L_add(Word32 L_var1, Word32 L_var2) +{ + Word32 L_var_out; + + L_var_out = L_var1 + L_var2; + + if (((L_var1 ^ L_var2) & MIN_32) == 0) { + if ((L_var_out ^ L_var1) & MIN_32) { + L_var_out = (L_var1 < 0) ? MIN_32 : MAX_32; + Overflow = 1; + } + } +#if (WMOPS) + multiCounter[currCounter].L_add++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_sub | + | | + | Purpose : | + | | + | 32 bits subtraction of the two 32 bits variables (L_var1-L_var2) with | + | overflow control and saturation; the result is set at +2147483647 when | + | overflow occurs or at -2147483648 when underflow occurs. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | L_var2 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ +Word32 L_sub(Word32 L_var1, Word32 L_var2) +{ + Word32 L_var_out; + + L_var_out = L_var1 - L_var2; + + if (((L_var1 ^ L_var2) & MIN_32) != 0) { + if ((L_var_out ^ L_var1) & MIN_32) { + L_var_out = (L_var1 < 0L) ? MIN_32 : MAX_32; + Overflow = 1; + } + } +#if (WMOPS) + multiCounter[currCounter].L_sub++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_add_c | + | | + | Purpose : | + | | + | Performs 32 bits addition of the two 32 bits variables (L_var1+L_var2+C)| + | with carry. No saturation. Generate carry and Overflow values. The car- | + | ry and overflow values are binary variables which can be tested and as- | + | signed values. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | L_var2 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + | | + | Caution : | + | | + | In some cases the Carry flag has to be cleared or set before using | + | operators which take into account its value. | + |___________________________________________________________________________| +*/ +Word32 L_add_c(Word32 L_var1, Word32 L_var2) +{ + Word32 L_var_out; + Word32 L_test; + Flag carry_int = 0; + + L_var_out = L_var1 + L_var2 + Carry; + + L_test = L_var1 + L_var2; + + if ((L_var1 > 0) && (L_var2 > 0) && (L_test < 0)) { + Overflow = 1; + carry_int = 0; + } + else { + if ((L_var1 < 0) && (L_var2 < 0)) { + if (L_test >= 0) { + Overflow = 1; + carry_int = 1; + } + else { + Overflow = 0; + carry_int = 1; + } + } + else { + if (((L_var1 ^ L_var2) < 0) && (L_test >= 0)) { + Overflow = 0; + carry_int = 1; + } + else { + Overflow = 0; + carry_int = 0; + } + } + } + + if (Carry) { + if (L_test == MAX_32) { + Overflow = 1; + Carry = carry_int; + } + else { + if (L_test == (Word32)0xFFFFFFFFL) { + Carry = 1; + } + else { + Carry = carry_int; + } + } + } + else { + Carry = carry_int; + } + +#if (WMOPS) + multiCounter[currCounter].L_add_c++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_sub_c | + | | + | Purpose : | + | | + | Performs 32 bits subtraction of the two 32 bits variables with carry | + | (borrow) : L_var1-L_var2-C. No saturation. Generate carry and Overflow | + | values. The carry and overflow values are binary variables which can | + | be tested and assigned values. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | L_var2 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + | | + | Caution : | + | | + | In some cases the Carry flag has to be cleared or set before using | + | operators which take into account its value. | + |___________________________________________________________________________| +*/ +Word32 L_sub_c(Word32 L_var1, Word32 L_var2) +{ + Word32 L_var_out; + Word32 L_test; + Flag carry_int = 0; + + if (Carry) { + Carry = 0; + if (L_var2 != MIN_32) { + L_var_out = L_add_c(L_var1, -L_var2); +#if (WMOPS) + multiCounter[currCounter].L_add_c--; +#endif + } + else { + L_var_out = L_var1 - L_var2; + if (L_var1 > 0L) { + Overflow = 1; + Carry = 0; + } + } + } + else { + L_var_out = L_var1 - L_var2 - (Word32)0X00000001L; + L_test = L_var1 - L_var2; + + if ((L_test < 0) && (L_var1 > 0) && (L_var2 < 0)) { + Overflow = 1; + carry_int = 0; + } + else if ((L_test > 0) && (L_var1 < 0) && (L_var2 > 0)) { + Overflow = 1; + carry_int = 1; + } + else if ((L_test > 0) && ((L_var1 ^ L_var2) > 0)) { + Overflow = 0; + carry_int = 1; + } + if (L_test == MIN_32) { + Overflow = 1; + Carry = carry_int; + } + else { + Carry = carry_int; + } + } + +#if (WMOPS) + multiCounter[currCounter].L_sub_c++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_negate | + | | + | Purpose : | + | | + | Negate the 32 bit variable L_var1 with saturation; saturate in the case | + | where input is -2147483648 (0x8000 0000). | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ +Word32 L_negate(Word32 L_var1) +{ + Word32 L_var_out; + + L_var_out = (L_var1 == MIN_32) ? MAX_32 : -L_var1; +#if (WMOPS) + multiCounter[currCounter].L_negate++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : mult_r | + | | + | Purpose : | + | | + | Same as mult with rounding, i.e.: | + | mult_r(var1,var2) = extract_l(L_shr(((var1 * var2) + 16384),15)) and | + | mult_r(-32768,-32768) = 32767. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +Word16 mult_r(Word16 var1, Word16 var2) +{ + Word16 var_out; + Word32 L_product_arr; + + L_product_arr = (Word32)var1 * (Word32)var2; /* product */ + L_product_arr += (Word32)0x00004000L; /* round */ + L_product_arr &= (Word32)0xffff8000L; + L_product_arr >>= 15; /* shift */ + + if (L_product_arr & (Word32)0x00010000L) /* sign extend when necessary */ + { + L_product_arr |= (Word32)0xffff0000L; + } + var_out = saturate(L_product_arr); +#if (WMOPS) + multiCounter[currCounter].mult_r++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_shl | + | | + | Purpose : | + | | + | Arithmetically shift the 32 bit input L_var1 left var2 positions. Zero | + | fill the var2 LSB of the result. If var2 is negative, arithmetically | + | shift L_var1 right by -var2 with sign extension. Saturate the result in | + | case of underflows or overflows. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ +Word32 L_shl(Word32 L_var1, Word16 var2) +{ + Word32 L_var_out = 0; + + if (var2 <= 0) { + if (var2 < -32) + var2 = -32; + L_var_out = L_shr(L_var1, -var2); +#if (WMOPS) + multiCounter[currCounter].L_shr--; +#endif + } + else { + for (; var2 > 0; var2--) { + if (L_var1 > (Word32)0X3fffffffL) { + Overflow = 1; + L_var_out = MAX_32; + break; + } + else { + if (L_var1 < (Word32)0xc0000000L) { + Overflow = 1; + L_var_out = MIN_32; + break; + } + } + L_var1 *= 2; + L_var_out = L_var1; + } + } +#if (WMOPS) + multiCounter[currCounter].L_shl++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_shr | + | | + | Purpose : | + | | + | Arithmetically shift the 32 bit input L_var1 right var2 positions with | + | sign extension. If var2 is negative, arithmetically shift L_var1 left | + | by -var2 and zero fill the -var2 LSB of the result. Saturate the result | + | in case of underflows or overflows. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ +Word32 L_shr(Word32 L_var1, Word16 var2) +{ + Word32 L_var_out; + + if (var2 < 0) { + if (var2 < -32) + var2 = -32; + L_var_out = L_shl(L_var1, -var2); +#if (WMOPS) + multiCounter[currCounter].L_shl--; +#endif + } + else { + if (var2 >= 31) { + L_var_out = (L_var1 < 0L) ? -1 : 0; + } + else { + if (L_var1 < 0) { + L_var_out = ~((~L_var1) >> var2); + } + else { + L_var_out = L_var1 >> var2; + } + } + } +#if (WMOPS) + multiCounter[currCounter].L_shr++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : shr_r | + | | + | Purpose : | + | | + | Same as shr(var1,var2) but with rounding. Saturate the result in case of| + | underflows or overflows : | + | - If var2 is greater than zero : | + | if (sub(shl(shr(var1,var2),1),shr(var1,sub(var2,1)))) | + | is equal to zero | + | then | + | shr_r(var1,var2) = shr(var1,var2) | + | else | + | shr_r(var1,var2) = add(shr(var1,var2),1) | + | - If var2 is less than or equal to zero : | + | shr_r(var1,var2) = shr(var1,var2). | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +Word16 shr_r(Word16 var1, Word16 var2) +{ + Word16 var_out; + + if (var2 > 15) { + var_out = 0; + } + else { + var_out = shr(var1, var2); +#if (WMOPS) + multiCounter[currCounter].shr--; +#endif + + if (var2 > 0) { + if ((var1 & ((Word16)1 << (var2 - 1))) != 0) { + var_out++; + } + } + } +#if (WMOPS) + multiCounter[currCounter].shr_r++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : mac_r | + | | + | Purpose : | + | | + | Multiply var1 by var2 and shift the result left by 1. Add the 32 bit | + | result to L_var3 with saturation. Round the LS 16 bits of the result | + | into the MS 16 bits with saturation and shift the result right by 16. | + | Return a 16 bit result. | + | mac_r(L_var3,var1,var2) = round(L_mac(L_var3,var1,var2)) | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var3 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 8000 <= L_var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +Word16 mac_r(Word32 L_var3, Word16 var1, Word16 var2) +{ + Word16 var_out; + + L_var3 = L_mac(L_var3, var1, var2); +#if (WMOPS) + multiCounter[currCounter].L_mac--; +#endif + L_var3 = L_add(L_var3, (Word32)0x00008000L); +#if (WMOPS) + multiCounter[currCounter].L_add--; +#endif + var_out = extract_h(L_var3); +#if (WMOPS) + multiCounter[currCounter].extract_h--; + multiCounter[currCounter].mac_r++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : msu_r | + | | + | Purpose : | + | | + | Multiply var1 by var2 and shift the result left by 1. Subtract the 32 | + | bit result to L_var3 with saturation. Round the LS 16 bits of the res- | + | ult into the MS 16 bits with saturation and shift the result right by | + | 16. Return a 16 bit result. | + | msu_r(L_var3,var1,var2) = round(L_msu(L_var3,var1,var2)) | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var3 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 8000 <= L_var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +Word16 msu_r(Word32 L_var3, Word16 var1, Word16 var2) +{ + Word16 var_out; + + L_var3 = L_msu(L_var3, var1, var2); +#if (WMOPS) + multiCounter[currCounter].L_msu--; +#endif + L_var3 = L_add(L_var3, (Word32)0x00008000L); +#if (WMOPS) + multiCounter[currCounter].L_add--; +#endif + var_out = extract_h(L_var3); +#if (WMOPS) + multiCounter[currCounter].extract_h--; + multiCounter[currCounter].msu_r++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_deposit_h | + | | + | Purpose : | + | | + | Deposit the 16 bit var1 into the 16 MS bits of the 32 bit output. The | + | 16 LS bits of the output are zeroed. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var_out <= 0x7fff 0000. | + |___________________________________________________________________________| +*/ +Word32 L_deposit_h(Word16 var1) +{ + Word32 L_var_out; + + L_var_out = (Word32)var1 << 16; +#if (WMOPS) + multiCounter[currCounter].L_deposit_h++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_deposit_l | + | | + | Purpose : | + | | + | Deposit the 16 bit var1 into the 16 LS bits of the 32 bit output. The | + | 16 MS bits of the output are sign extended. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0xFFFF 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ +Word32 L_deposit_l(Word16 var1) +{ + Word32 L_var_out; + + L_var_out = (Word32)var1; +#if (WMOPS) + multiCounter[currCounter].L_deposit_l++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_shr_r | + | | + | Purpose : | + | | + | Same as L_shr(L_var1,var2) but with rounding. Saturate the result in | + | case of underflows or overflows : | + | - If var2 is greater than zero : | + | if (L_sub(L_shl(L_shr(L_var1,var2),1),L_shr(L_var1,sub(var2,1))))| + | is equal to zero | + | then | + | L_shr_r(L_var1,var2) = L_shr(L_var1,var2) | + | else | + | L_shr_r(L_var1,var2) = L_add(L_shr(L_var1,var2),1) | + | - If var2 is less than or equal to zero : | + | L_shr_r(L_var1,var2) = L_shr(L_var1,var2). | + | | + | Complexity weight : 3 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var1 <= 0x7fff ffff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ +Word32 L_shr_r(Word32 L_var1, Word16 var2) +{ + Word32 L_var_out; + + if (var2 > 31) { + L_var_out = 0; + } + else { + L_var_out = L_shr(L_var1, var2); +#if (WMOPS) + multiCounter[currCounter].L_shr--; +#endif + if (var2 > 0) { + if ((L_var1 & ((Word32)1 << (var2 - 1))) != 0) { + L_var_out++; + } + } + } +#if (WMOPS) + multiCounter[currCounter].L_shr_r++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_abs | + | | + | Purpose : | + | | + | Absolute value of L_var1; Saturate in case where the input is | + | -214783648 | + | | + | Complexity weight : 3 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x0000 0000 <= var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ +Word32 L_abs(Word32 L_var1) +{ + Word32 L_var_out; + + if (L_var1 == MIN_32) { + L_var_out = MAX_32; + } + else { + if (L_var1 < 0) { + L_var_out = -L_var1; + } + else { + L_var_out = L_var1; + } + } + +#if (WMOPS) + multiCounter[currCounter].L_abs++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_sat | + | | + | Purpose : | + | | + | 32 bit L_var1 is set to 2147483647 if an overflow occured or to | + | -2147483648 if an underflow occured on the most recent L_add_c, | + | L_sub_c, L_macNs or L_msuNs operations. The carry and overflow values | + | are binary values which can be tested and assigned values. | + | | + | Complexity weight : 4 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ +Word32 L_sat(Word32 L_var1) +{ + Word32 L_var_out; + + L_var_out = L_var1; + + if (Overflow) { + + if (Carry) { + L_var_out = MIN_32; + } + else { + L_var_out = MAX_32; + } + + Carry = 0; + Overflow = 0; + } +#if (WMOPS) + multiCounter[currCounter].L_sat++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : norm_s | + | | + | Purpose : | + | | + | Produces the number of left shift needed to normalize the 16 bit varia- | + | ble var1 for positive values on the interval with minimum of 16384 and | + | maximum of 32767, and for negative values on the interval with minimum | + | of -32768 and maximum of -16384; in order to normalize the result, the | + | following operation must be done : | + | norm_var1 = shl(var1,norm_s(var1)). | + | | + | Complexity weight : 15 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 0000 <= var_out <= 0x0000 000f. | + |___________________________________________________________________________| +*/ +Word16 norm_s(Word16 var1) +{ + Word16 var_out; + + if (var1 == 0) { + var_out = 0; + } + else { + if (var1 == (Word16)0xffff) { + var_out = 15; + } + else { + if (var1 < 0) { + var1 = ~var1; + } + for (var_out = 0; var1 < 0x4000; var_out++) { + var1 <<= 1; + } + } + } + +#if (WMOPS) + multiCounter[currCounter].norm_s++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : div_s | + | | + | Purpose : | + | | + | Produces a result which is the fractional integer division of var1 by | + | var2; var1 and var2 must be positive and var2 must be greater or equal | + | to var1; the result is positive (leading bit equal to 0) and truncated | + | to 16 bits. | + | If var1 = var2 then div(var1,var2) = 32767. | + | | + | Complexity weight : 18 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 0000 <= var1 <= var2 and var2 != 0. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : var1 <= var2 <= 0x0000 7fff and var2 != 0. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 0000 <= var_out <= 0x0000 7fff. | + | It's a Q15 value (point between b15 and b14). | + |___________________________________________________________________________| +*/ +Word16 div_s(Word16 var1, Word16 var2) +{ + Word16 var_out = 0; + Word16 iteration; + Word32 L_num; + Word32 L_denom; + + if ((var1 > var2) || (var1 < 0) || (var2 < 0)) { + printf("Division Error var1=%d var2=%d\n", var1, var2); + abort(); /* exit (0); */ + } + if (var2 == 0) { + printf("Division by 0, Fatal error \n"); + abort(); /* exit (0); */ + } + if (var1 == 0) { + var_out = 0; + } + else { + if (var1 == var2) { + var_out = MAX_16; + } + else { + L_num = L_deposit_l(var1); +#if (WMOPS) + multiCounter[currCounter].L_deposit_l--; +#endif + L_denom = L_deposit_l(var2); +#if (WMOPS) + multiCounter[currCounter].L_deposit_l--; +#endif + + for (iteration = 0; iteration < 15; iteration++) { + var_out <<= 1; + L_num <<= 1; + + if (L_num >= L_denom) { + L_num = L_sub(L_num, L_denom); +#if (WMOPS) + multiCounter[currCounter].L_sub--; +#endif + var_out = add(var_out, 1); +#if (WMOPS) + multiCounter[currCounter].add--; +#endif + } + } + } + } + +#if (WMOPS) + multiCounter[currCounter].div_s++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : norm_l | + | | + | Purpose : | + | | + | Produces the number of left shifts needed to normalize the 32 bit varia-| + | ble L_var1 for positive values on the interval with minimum of | + | 1073741824 and maximum of 2147483647, and for negative values on the in-| + | terval with minimum of -2147483648 and maximum of -1073741824; in order | + | to normalize the result, the following operation must be done : | + | norm_L_var1 = L_shl(L_var1,norm_l(L_var1)). | + | | + | Complexity weight : 30 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 0000 <= var_out <= 0x0000 001f. | + |___________________________________________________________________________| +*/ +Word16 norm_l(Word32 L_var1) +{ + Word16 var_out; + + if (L_var1 == 0) { + var_out = 0; + } + else { + if (L_var1 == (Word32)0xffffffffL) { + var_out = 31; + } + else { + if (L_var1 < 0) { + L_var1 = ~L_var1; + } + for (var_out = 0; L_var1 < (Word32)0x40000000L; var_out++) { + L_var1 <<= 1; + } + } + } + +#if (WMOPS) + multiCounter[currCounter].norm_l++; +#endif + return (var_out); +} diff --git a/vocoder/imbe/basic_op.h b/vocoder/imbe/basic_op.h new file mode 100644 index 0000000..2c52cdc --- /dev/null +++ b/vocoder/imbe/basic_op.h @@ -0,0 +1,82 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ +#ifndef __BASIC_OP_H__ +#define __BASIC_OP_H__ + +// --------------------------------------------------------------------------- +// Constants and Globals +// --------------------------------------------------------------------------- +extern Flag Overflow; +extern Flag Carry; + +#define MAX_32 (Word32)0x7fffffffL +#define MIN_32 (Word32)0x80000000L + +#define MAX_16 (Word16)0x7fff +#define MIN_16 (Word16)0x8000 + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +Word16 add(Word16 var1, Word16 var2); /* Short add, 1 */ +Word16 sub(Word16 var1, Word16 var2); /* Short sub, 1 */ +Word16 abs_s(Word16 var1); /* Short abs, 1 */ +Word16 shl(Word16 var1, Word16 var2); /* Short shift left, 1 */ +Word16 shr(Word16 var1, Word16 var2); /* Short shift right, 1 */ +Word16 mult(Word16 var1, Word16 var2); /* Short mult, 1 */ +Word32 L_mult(Word16 var1, Word16 var2); /* Long mult, 1 */ +Word16 negate(Word16 var1); /* Short negate, 1 */ +Word16 extract_h(Word32 L_var1); /* Extract high, 1 */ +Word16 extract_l(Word32 L_var1); /* Extract low, 1 */ +Word16 L_round(Word32 L_var1); /* Round, 1 */ +Word32 L_mac(Word32 L_var3, Word16 var1, Word16 var2); /* Mac, 1 */ +Word32 L_msu(Word32 L_var3, Word16 var1, Word16 var2); /* Msu, 1 */ +Word32 L_macNs(Word32 L_var3, Word16 var1, Word16 var2); /* Mac without + sat, 1 */ +Word32 L_msuNs(Word32 L_var3, Word16 var1, Word16 var2); /* Msu without + sat, 1 */ +Word32 L_add(Word32 L_var1, Word32 L_var2); /* Long add, 2 */ +Word32 L_sub(Word32 L_var1, Word32 L_var2); /* Long sub, 2 */ +Word32 L_add_c(Word32 L_var1, Word32 L_var2); /* Long add with c, 2 */ +Word32 L_sub_c(Word32 L_var1, Word32 L_var2); /* Long sub with c, 2 */ +Word32 L_negate(Word32 L_var1); /* Long negate, 2 */ +Word16 mult_r(Word16 var1, Word16 var2); /* Mult with round, 2 */ +Word32 L_shl(Word32 L_var1, Word16 var2); /* Long shift left, 2 */ +Word32 L_shr(Word32 L_var1, Word16 var2); /* Long shift right, 2*/ +Word16 shr_r(Word16 var1, Word16 var2); /* Shift right with + round, 2 */ +Word16 mac_r(Word32 L_var3, Word16 var1, Word16 var2); /* Mac with + rounding,2 */ +Word16 msu_r(Word32 L_var3, Word16 var1, Word16 var2); /* Msu with + rounding,2 */ +Word32 L_deposit_h(Word16 var1); /* 16 bit var1 -> MSB, 2 */ +Word32 L_deposit_l(Word16 var1); /* 16 bit var1 -> LSB, 2 */ + +Word32 L_shr_r(Word32 L_var1, Word16 var2); /* Long shift right with + round, 3 */ +Word32 L_abs(Word32 L_var1); /* Long abs, 3 */ +Word32 L_sat(Word32 L_var1); /* Long saturation, 4 */ +Word16 norm_s(Word16 var1); /* Short norm, 15 */ +Word16 div_s(Word16 var1, Word16 var2); /* Short division, 18 */ +Word16 norm_l(Word32 L_var1); /* Long norm, 30 */ + +#endif // __BASIC_OP_H__ diff --git a/vocoder/imbe/ch_decode.cpp b/vocoder/imbe/ch_decode.cpp new file mode 100644 index 0000000..3b5e340 --- /dev/null +++ b/vocoder/imbe/ch_decode.cpp @@ -0,0 +1,178 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/globals.h" +#include "imbe/imbe.h" +#include "imbe/basic_op.h" +#include "imbe/ch_decode.h" +#include "imbe/aux_sub.h" + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +void decode_frame_vector(IMBE_PARAM* imbe_param, Word16* frame_vector) +{ + Word16 bit_stream[BIT_STREAM_LEN]; + Word16 i, vec_num, tmp, tmp1, tmp2, bit_thr, shift; + Word16* b_ptr, *ba_ptr, index0; + Word32 L_tmp; + + imbe_param->b_vec[0] = (shr(frame_vector[0], 4) & 0xFC) | (shr(frame_vector[7], 1) & 0x3); + + if (imbe_param->b_vec[0] < 0 || imbe_param->b_vec[0] > 207) + return; // If we return here IMBE parameters from previous frame will be used (frame repeating) + + tmp = ((imbe_param->b_vec[0] & 0xFF) << 1) + 0x4F; // Convert b_vec[0] to unsigned Q15.1 format and add 39.5 + + //imbe_param->ff = 4./((double)imbe_param->b_vec[0] + 39.5); + + // Calculate fundamental frequency with higher precession + shift = norm_s(tmp); + tmp1 = tmp << shift; + + tmp2 = div_s(0x4000, tmp1); + imbe_param->fund_freq = L_shr(L_deposit_h(tmp2), 11 - shift); + + L_tmp = L_sub(0x40000000, L_mult(tmp1, tmp2)); + tmp2 = div_s(extract_l(L_shr(L_tmp, 2)), tmp1); + L_tmp = L_shr(L_deposit_l(tmp2), 11 - shift - 2); + imbe_param->fund_freq = L_add(imbe_param->fund_freq, L_tmp); + + //printf("%X %X \n", imbe_param->fund_freq, (Word32)(imbe_param->ff * (double)((UWord32)1<<31))); + + tmp = (tmp + 0x2) >> 3; // Calculate (b0 + 39.5 + 1)/4 + imbe_param->num_harms = ((UWord32)CNST_0_9254_Q0_16 * tmp) >> 16; + + if (imbe_param->num_harms <= 36) + imbe_param->num_bands = extract_h((UWord32)(imbe_param->num_harms + 2) * CNST_0_33_Q0_16); // fix((L+2)/3) + else + imbe_param->num_bands = NUM_BANDS_MAX; + + // Convert input vector (from b_3 to b_L+1) to bit stream + bit_stream[0] = (frame_vector[0] & 0x4) ? 1 : 0; + bit_stream[1] = (frame_vector[0] & 0x2) ? 1 : 0; + bit_stream[2] = (frame_vector[0] & 0x1) ? 1 : 0; + + bit_stream[BIT_STREAM_LEN - 3] = (frame_vector[7] & 0x40) ? 1 : 0; + bit_stream[BIT_STREAM_LEN - 2] = (frame_vector[7] & 0x20) ? 1 : 0; + bit_stream[BIT_STREAM_LEN - 1] = (frame_vector[7] & 0x10) ? 1 : 0; + + + index0 = 3 + 3 * 12 - 1; + for (vec_num = 3; vec_num >= 1; vec_num--) { + tmp = frame_vector[vec_num]; + for (i = 0; i < 12; i++) { + bit_stream[index0] = (tmp & 0x1) ? 1 : 0; + tmp >>= 1; + index0--; + } + } + + index0 = 3 + 3 * 12 + 3 * 11 - 1; + for (vec_num = 6; vec_num >= 4; vec_num--) { + tmp = frame_vector[vec_num]; + for (i = 0; i < 11; i++) { + bit_stream[index0] = (tmp & 0x1) ? 1 : 0; + tmp >>= 1; + index0--; + } + } + + // Rebuild b1 + index0 = 3 + 3 * 12; + tmp = 0; + for (i = 0; i < imbe_param->num_bands; i++) + tmp = (tmp << 1) | bit_stream[index0++]; + + imbe_param->b_vec[1] = tmp; + + // Rebuild b2 + tmp = 0; + tmp |= bit_stream[index0++] << 1; + tmp |= bit_stream[index0++]; + imbe_param->b_vec[2] = (frame_vector[0] & 0x38) | (tmp << 1) | (shr(frame_vector[7], 3) & 0x01); + + // Shift the rest of sequence + tmp = imbe_param->num_bands + 2; // shift + for (; index0 < BIT_STREAM_LEN; index0++) + bit_stream[index0 - tmp] = bit_stream[index0]; + + // Priority ReScanning + b_ptr = &imbe_param->b_vec[3]; + ba_ptr = imbe_param->bit_alloc; + for (i = 0; i < B_NUM; i++) + ba_ptr[i] = b_ptr[i] = 0; + + + // Unpack bit allocation table's item + get_bit_allocation(imbe_param->num_harms, imbe_param->bit_alloc); + + index0 = 0; + bit_thr = (imbe_param->num_harms == 0xb) ? 9 : ba_ptr[0]; + + while (index0 < BIT_STREAM_LEN - imbe_param->num_bands - 2) { + for (i = 0; i < imbe_param->num_harms - 1; i++) + if (bit_thr && bit_thr <= ba_ptr[i]) + b_ptr[i] = (b_ptr[i] << 1) | bit_stream[index0++]; + bit_thr--; + } + + // Synchronization Bit Decoding + imbe_param->b_vec[imbe_param->num_harms + 2] = frame_vector[7] & 1; +} + +void v_uv_decode(IMBE_PARAM* imbe_param) +{ + Word16 num_harms; + Word16 num_bands; + Word16 vu_vec, * p_v_uv_dsn, mask, i, uv_cnt; + + num_harms = imbe_param->num_harms; + num_bands = imbe_param->num_bands; + vu_vec = imbe_param->b_vec[1]; + + p_v_uv_dsn = imbe_param->v_uv_dsn; + + mask = 1 << (num_bands - 1); + + v_zap(p_v_uv_dsn, NUM_HARMS_MAX); + + i = 0; uv_cnt = 0; + while (num_harms--) { + if (vu_vec & mask) + *p_v_uv_dsn++ = 1; + else { + *p_v_uv_dsn++ = 0; + uv_cnt++; + } + + if (++i == 3) { + if (num_bands > 1) { + num_bands--; + mask >>= 1; + } + i = 0; + } + } + imbe_param->l_uv = uv_cnt; +} diff --git a/vocoder/imbe/ch_decode.h b/vocoder/imbe/ch_decode.h new file mode 100644 index 0000000..3178165 --- /dev/null +++ b/vocoder/imbe/ch_decode.h @@ -0,0 +1,39 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ +#ifndef __CH_DECODE_H__ +#define __CH_DECODE_H__ + +#include "imbe/typedef.h" + +// --------------------------------------------------------------------------- +// Macros +// --------------------------------------------------------------------------- + +#define BIT_STREAM_LEN (3 + 3*12 + 3*11 + 3) + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +void decode_frame_vector(IMBE_PARAM *imbe_param, Word16 *frame_vector); +void v_uv_decode(IMBE_PARAM *imbe_param); + +#endif // __CH_DECODE_H__ diff --git a/vocoder/imbe/ch_encode.cpp b/vocoder/imbe/ch_encode.cpp new file mode 100644 index 0000000..4581336 --- /dev/null +++ b/vocoder/imbe/ch_encode.cpp @@ -0,0 +1,106 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/globals.h" +#include "imbe/imbe.h" +#include "imbe/basic_op.h" +#include "imbe/ch_encode.h" +#include "imbe/aux_sub.h" + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +void encode_frame_vector(IMBE_PARAM* imbe_param, Word16* frame_vector) +{ + Word16 bit_stream[EN_BIT_STREAM_LEN], index0, bit_thr, bit_mask, i; + Word16 vec_num, num_harms, num_bands, tmp; + Word16* ba_ptr, *b_ptr; + + num_harms = imbe_param->num_harms; + num_bands = imbe_param->num_bands; + + v_zap(frame_vector, 8); + + // Unpack bit allocation table's item + get_bit_allocation(num_harms, imbe_param->bit_alloc); + + // Priority Scanning + index0 = 0; + ba_ptr = imbe_param->bit_alloc; + bit_thr = (num_harms == 0xb) ? 9 : ba_ptr[0]; + bit_mask = shl(1, bit_thr - 1); + + while (index0 < EN_BIT_STREAM_LEN - (num_bands - 3)) { + b_ptr = &imbe_param->b_vec[3]; + for (i = 0; i < num_harms - 1; i++) + if (bit_thr && bit_thr <= ba_ptr[i]) + bit_stream[index0++] = (b_ptr[i] & bit_mask) ? 1 : 0; + + bit_thr--; + bit_mask = shr(bit_mask, 1); + } + + frame_vector[0] = shl(imbe_param->b_vec[0] & 0xFC, 4) | (imbe_param->b_vec[2] & 0x38); + + index0 = 0; + frame_vector[0] |= (bit_stream[index0++]) ? 4 : 0; + frame_vector[0] |= (bit_stream[index0++]) ? 2 : 0; + frame_vector[0] |= (bit_stream[index0++]) ? 1 : 0; + + for (vec_num = 1; vec_num <= 3; vec_num++) { + tmp = 0; + for (i = 0; i < 12; i++) { + tmp <<= 1; + tmp |= bit_stream[index0++]; + } + frame_vector[vec_num] = tmp; + } + + index0 -= num_bands + 2; + + bit_mask = shl(1, num_bands - 1); + for (i = 0; i < num_bands; i++) { + bit_stream[index0++] = (imbe_param->b_vec[1] & bit_mask) ? 1 : 0; + bit_mask >>= 1; + } + + bit_stream[index0++] = (imbe_param->b_vec[2] & 0x04) ? 1 : 0; + bit_stream[index0++] = (imbe_param->b_vec[2] & 0x02) ? 1 : 0; + + index0 -= num_bands + 2; + + for (vec_num = 4; vec_num <= 6; vec_num++) { + tmp = 0; + for (i = 0; i < 11; i++) { + tmp <<= 1; + tmp |= bit_stream[index0++]; + } + frame_vector[vec_num] = tmp; + } + + frame_vector[7] = shl(imbe_param->b_vec[0] & 0x03, 1) | shl(imbe_param->b_vec[2] & 0x01, 3); + frame_vector[7] |= (bit_stream[index0++]) ? 0x40 : 0; + frame_vector[7] |= (bit_stream[index0++]) ? 0x20 : 0; + frame_vector[7] |= (bit_stream[index0++]) ? 0x10 : 0; + frame_vector[7] |= (imbe_param->b_vec[num_harms + 2]) ? 0x01 : 0; +} diff --git a/vocoder/imbe/ch_encode.h b/vocoder/imbe/ch_encode.h new file mode 100644 index 0000000..fb738b0 --- /dev/null +++ b/vocoder/imbe/ch_encode.h @@ -0,0 +1,36 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ +#ifndef __CH_ENCODE_H__ +#define __CH_ENCODE_H__ + +// --------------------------------------------------------------------------- +// Macros +// --------------------------------------------------------------------------- + +#define EN_BIT_STREAM_LEN (3 + 3*12 + 6 + 2*11 + 3) + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +void encode_frame_vector(IMBE_PARAM *imbe_param, Word16 *frame_vector); + +#endif // __CH_ENCODE_H__ diff --git a/vocoder/imbe/dc_rmv.cpp b/vocoder/imbe/dc_rmv.cpp new file mode 100644 index 0000000..ca11a4c --- /dev/null +++ b/vocoder/imbe/dc_rmv.cpp @@ -0,0 +1,67 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/globals.h" +#include "imbe/imbe.h" +#include "imbe/aux_sub.h" +#include "imbe/basic_op.h" +#include "imbe/math_sub.h" +#include "imbe/dc_rmv.h" + +#define CNST_0_99_Q1_15 0x7EB8 + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// PURPOSE: +// High-pass filter to remove DC +// +// +// INPUT: +// *sigin - pointer to input signal buffer +// *sigout - pointer to output signal buffer +// *mem - pointer to filter's memory element +// len - number of input signal samples +// +// OUTPUT: +// None +// +// RETURN: +// Saved filter state in mem +// +//----------------------------------------------------------------------------- +void dc_rmv(Word16* sigin, Word16* sigout, Word32* mem, Word16 len) +{ + Word32 L_tmp, L_mem; + + L_mem = *mem; + while (len--) { + L_tmp = L_deposit_h(*sigin++); + L_mem = L_add(L_mem, L_tmp); + *sigout++ = L_round(L_mem); + L_mem = L_mpy_ls(L_mem, CNST_0_99_Q1_15); + L_mem = L_sub(L_mem, L_tmp); + } + *mem = L_mem; +} diff --git a/vocoder/imbe/dc_rmv.h b/vocoder/imbe/dc_rmv.h new file mode 100644 index 0000000..d08921b --- /dev/null +++ b/vocoder/imbe/dc_rmv.h @@ -0,0 +1,48 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ +#ifndef __DC_RMV_H__ +#define __DC_RMV_H__ + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// PURPOSE: +// High-pass filter to remove DC +// +// +// INPUT: +// *sigin - pointer to input signal buffer +// *sigout - pointer to output signal buffer +// *mem - pointer to filter's memory element +// len - number of input signal samples +// +// OUTPUT: +// None +// +// RETURN: +// Saved filter state in mem +// +//----------------------------------------------------------------------------- +void dc_rmv(Word16 *sigin, Word16 *sigout, Word32 *mem, Word16 len); + +#endif // __DC_RMV_H__ diff --git a/vocoder/imbe/decode.cpp b/vocoder/imbe/decode.cpp new file mode 100644 index 0000000..640efd0 --- /dev/null +++ b/vocoder/imbe/decode.cpp @@ -0,0 +1,65 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/globals.h" +#include "imbe/imbe.h" +#include "imbe/ch_decode.h" +#include "imbe/sa_enh.h" +#include "imbe/basic_op.h" +#include "imbe/aux_sub.h" +#include "imbe/imbe_vocoder.h" + +#include + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- + +void imbe_vocoder::decode_init(IMBE_PARAM* imbe_param) +{ + v_synt_init(); + uv_synt_init(); + sa_decode_init(); + + // Make previous frame for the first frame + memset((char*)imbe_param, 0, sizeof(IMBE_PARAM)); + imbe_param->fund_freq = 0x0cf6474a; + imbe_param->num_harms = 9; + imbe_param->num_bands = 3; + +} + +void imbe_vocoder::decode(IMBE_PARAM* imbe_param, Word16* frame_vector, Word16* snd) +{ + Word16 snd_tmp[FRAME]; + Word16 j; + + decode_frame_vector(imbe_param, frame_vector); + v_uv_decode(imbe_param); + sa_decode(imbe_param); + sa_enh(imbe_param); + v_synt(imbe_param, snd); + uv_synt(imbe_param, snd_tmp); + + for (j = 0; j < FRAME; j++) + snd[j] = add(snd[j], snd_tmp[j]); +} diff --git a/vocoder/imbe/dsp_sub.cpp b/vocoder/imbe/dsp_sub.cpp new file mode 100644 index 0000000..70d1e41 --- /dev/null +++ b/vocoder/imbe/dsp_sub.cpp @@ -0,0 +1,260 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/basic_op.h" +#include "imbe/imbe.h" +#include "imbe/globals.h" +#include "imbe/tbls.h" +#include "imbe/math_sub.h" +#include "imbe/imbe_vocoder.h" + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// PURPOSE: +// Perform inverse DCT +// +// +// INPUT: +// in - pointer to input data +// m_lim - input data's size +// i_lim - result's size +// out - pointer to save result +// +// OUTPUT: +// None +// +// RETURN: +// Saved in out result of conversion +// +//----------------------------------------------------------------------------- +void imbe_vocoder::idct(Word16* in, Word16 m_lim, Word16 i_lim, Word16* out) +{ + UWord16 angl_step, angl_intl, angl_intl_2; + UWord16 angl_acc; + Word32 sum; + Word16 i, m; + + if (m_lim == 1) { + angl_intl = CNST_0_5_Q1_15; + angl_intl_2 = CNST_1_0_Q1_15; + } + else { + angl_intl = div_s((Word16)CNST_0_5_Q5_11, m_lim << 11); // calculate 0.5/m_lim + angl_intl_2 = shl(angl_intl, 1); + } + + angl_step = angl_intl; + for (i = 0; i < i_lim; i++) { + sum = 0; + angl_acc = angl_step; + for (m = 1; m < m_lim; m++) { + sum = L_add(sum, L_shr(L_mult(in[m], cos_fxp(angl_acc)), 7)); + angl_acc += angl_step; + } + sum = L_add(sum, L_shr(L_deposit_h(in[0]), 8)); + out[i] = extract_l(L_shr_r(sum, 8)); + angl_step += angl_intl_2; + } +} + +//----------------------------------------------------------------------------- +// PURPOSE: +// Perform DCT +// +// +// INPUT: +// in - pointer to input data +// m_lim - input data's size +// i_lim - result's size +// out - pointer to save result +// +// OUTPUT: +// None +// +// RETURN: +// Saved in out result of conversion +// +//----------------------------------------------------------------------------- +void imbe_vocoder::dct(Word16* in, Word16 m_lim, Word16 i_lim, Word16* out) +{ + UWord16 angl_step, angl_intl, angl_intl_2, angl_begin; + UWord16 angl_acc; + Word32 sum; + Word16 i, m; + + if (m_lim == 1) { + angl_intl = CNST_0_5_Q1_15; + angl_intl_2 = CNST_1_0_Q1_15; + } + else { + angl_intl = div_s((Word16)CNST_0_5_Q5_11, m_lim << 11); // calculate 0.5/m_lim + angl_intl_2 = shl(angl_intl, 1); + } + + // Calculate first coefficient + sum = 0; + for (m = 0; m < m_lim; m++) + sum = L_add(sum, L_deposit_l(in[m])); + out[0] = extract_l(L_mpy_ls(sum, angl_intl_2)); + + // Calculate the others coefficients + angl_begin = angl_intl; + angl_step = angl_intl_2; + for (i = 1; i < i_lim; i++) { + sum = 0; + angl_acc = angl_begin; + for (m = 0; m < m_lim; m++) { + sum = L_add(sum, L_deposit_l(mult(in[m], cos_fxp(angl_acc)))); + angl_acc += angl_step; + } + out[i] = extract_l(L_mpy_ls(sum, angl_intl_2)); + + angl_step += angl_intl_2; + angl_begin += angl_intl; + } +} + +void imbe_vocoder::fft_init(void) +{ + Word16 i, fft_len2, shift, step, theta; + + fft_len2 = shr(FFTLENGTH, 1); + shift = norm_s(fft_len2); + step = shl(2, shift); + theta = 0; + + for (i = 0; i <= fft_len2; i++) { + wr_array[i] = cos_fxp(theta); + wi_array[i] = sin_fxp(theta); + if (i >= (fft_len2 - 1)) + theta = ONE_Q15; + else + theta = add(theta, step); + } +} + +// Subroutine FFT: Fast Fourier Transform +// *************************************************************** +// * Replaces data by its DFT, if isign is 1, or replaces data * +// * by inverse DFT times nn if isign is -1. data is a complex * +// * array of length nn, input as a real array of length 2*nn. * +// * nn MUST be an integer power of two. This is not checked * +// * The real part of the number should be in the zeroeth * +// * of data , and the imaginary part should be in the next * +// * element. Hence all the real parts should have even indeces * +// * and the imaginary parts, odd indeces. * +// * * +// * Data is passed in an array starting in position 0, but the * +// * code is copied from Fortran so uses an internal pointer * +// * which accesses position 0 as position 1, etc. * +// * * +// * This code uses e+jwt sign convention, so isign should be * +// * reversed for e-jwt. * +// *************************************************************** +// +// Q values: +// datam1 - Q14 +// isign - Q15 + +#define SWAP(a,b) temp1 = (a);(a) = (b); (b) = temp1 + +void imbe_vocoder::fft(Word16* datam1, Word16 nn, Word16 isign) +{ + Word16 n, mmax, m, j, istep, i; + Word16 wr, wi, temp1; + Word32 L_tempr, L_tempi; + Word16* data; + Word32 L_temp1, L_temp2; + Word16 index, index_step; + + // Use pointer indexed from 1 instead of 0 + data = &datam1[-1]; + + n = shl(nn, 1); + j = 1; + for (i = 1; i < n; i += 2) { + if (j > i) { + SWAP(data[j], data[i]); + SWAP(data[j + 1], data[i + 1]); + } + m = nn; + while (m >= 2 && j > m) { + j = sub(j, m); + m = shr(m, 1); + } + j = add(j, m); + } + mmax = 2; + + // initialize index step + index_step = nn; + + while (n > mmax) { + istep = shl(mmax, 1); // istep = 2 * mmax + + index = 0; + index_step = shr(index_step, 1); + + wr = ONE_Q15; + wi = 0; + for (m = 1; m < mmax; m += 2) { + for (i = m; i <= n; i += istep) { + j = i + mmax; + + // tempr = wr * data[j] - wi * data[j+1] + L_temp1 = L_shr(L_mult(wr, data[j]), 1); + L_temp2 = L_shr(L_mult(wi, data[j + 1]), 1); + L_tempr = L_sub(L_temp1, L_temp2); + + // tempi = wr * data[j+1] + wi * data[j] + L_temp1 = L_shr(L_mult(wr, data[j + 1]), 1); + L_temp2 = L_shr(L_mult(wi, data[j]), 1); + L_tempi = L_add(L_temp1, L_temp2); + + + // data[j] = data[i] - tempr + L_temp1 = L_shr(L_deposit_h(data[i]), 1); + data[j] = L_round(L_sub(L_temp1, L_tempr)); + + // data[i] += tempr + data[i] = L_round(L_add(L_temp1, L_tempr)); + + // data[j+1] = data[i+1] - tempi + L_temp1 = L_shr(L_deposit_h(data[i + 1]), 1); + data[j + 1] = L_round(L_sub(L_temp1, L_tempi)); + + // data[i+1] += tempi + data[i + 1] = L_round(L_add(L_temp1, L_tempi)); + } + index = add(index, index_step); + wr = wr_array[index]; + if (isign < 0) + wi = negate(wi_array[index]); + else + wi = wi_array[index]; + } + mmax = istep; + } +} diff --git a/vocoder/imbe/encode.cpp b/vocoder/imbe/encode.cpp new file mode 100644 index 0000000..ba7c3db --- /dev/null +++ b/vocoder/imbe/encode.cpp @@ -0,0 +1,91 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/globals.h" +#include "imbe/imbe.h" +#include "imbe/basic_op.h" +#include "imbe/aux_sub.h" +#include "imbe/tbls.h" +#include "imbe/dc_rmv.h" +#include "imbe/pe_lpf.h" +#include "imbe/pitch_est.h" +#include "imbe/pitch_ref.h" +#include "imbe/ch_encode.h" +#include "imbe/imbe_vocoder.h" + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- + +void imbe_vocoder::encode_init(void) +{ + v_zap(pitch_est_buf, PITCH_EST_BUF_SIZE); + v_zap(pitch_ref_buf, PITCH_EST_BUF_SIZE); + v_zap(pe_lpf_mem, PE_LPF_ORD); + pitch_est_init(); + fft_init(); + dc_rmv_mem = 0; + sa_encode_init(); + pitch_ref_init(); +} + +void imbe_vocoder::encode(IMBE_PARAM* imbe_param, Word16* frame_vector, Word16* snd) +{ + Word16 i; + Word16* wr_ptr, *sig_ptr; + + for (i = 0; i < PITCH_EST_BUF_SIZE - FRAME; i++) { + pitch_est_buf[i] = pitch_est_buf[i + FRAME]; + pitch_ref_buf[i] = pitch_ref_buf[i + FRAME]; + } + + dc_rmv(snd, &pitch_ref_buf[PITCH_EST_BUF_SIZE - FRAME], &dc_rmv_mem, FRAME); + pe_lpf(&pitch_ref_buf[PITCH_EST_BUF_SIZE - FRAME], &pitch_est_buf[PITCH_EST_BUF_SIZE - FRAME], pe_lpf_mem, FRAME); + + pitch_est(imbe_param, pitch_est_buf); + + // + // Speech windowing and FFT calculation + // + wr_ptr = (Word16*)wr; + sig_ptr = &pitch_ref_buf[40]; + for (i = 146; i < 256; i++) { + fft_buf[i].re = mult(*sig_ptr++, *wr_ptr++); + fft_buf[i].im = 0; + } + fft_buf[0].re = *sig_ptr++; + fft_buf[0].im = 0; + wr_ptr--; + for (i = 1; i < 111; i++) { + fft_buf[i].re = mult(*sig_ptr++, *wr_ptr--); + fft_buf[i].im = 0; + } + for (i = 111; i < 146; i++) + fft_buf[i].re = fft_buf[i].im = 0; + + fft((Word16*)&fft_buf, FFTLENGTH, 1); + + pitch_ref(imbe_param, fft_buf); + v_uv_det(imbe_param, fft_buf); + sa_encode(imbe_param); + encode_frame_vector(imbe_param, frame_vector); +} diff --git a/vocoder/imbe/globals.h b/vocoder/imbe/globals.h new file mode 100644 index 0000000..a450547 --- /dev/null +++ b/vocoder/imbe/globals.h @@ -0,0 +1,66 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ +#ifndef __IMBE_GLOBALS_H__ +#define __IMBE_GLOBALS_H__ + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +//#define PI (double)3.1415926535897932384626433832795 + +#define CNST_0_9254_Q0_16 60647 // 0.9254 in unsigned Q0.16 format +#define CNST_0_33_Q0_16 0x5556 // 0.(3) = 1/3 in unsigned Q0.16 format + + +#define CNST_ONE_Q8_24 0x01000000 +#define CNST_0_7_Q1_15 0x599A +#define CNST_0_4_Q1_15 0x3333 +#define CNST_0_03_Q1_15 0x03D7 +#define CNST_0_05_Q1_15 0x0666 + +#define CNST_1_125_Q8_8 0x0120 +#define CNST_0_5_Q8_8 0x0080 +#define CNST_0_125_Q8_8 0x0020 +#define CNST_0_25_Q8_8 0x0040 + +#define CNST_0_8717_Q1_15 0x6F94 +#define CNST_0_0031_Q1_15 0x0064 +#define CNST_0_48_Q4_12 0x07AE +#define CNST_1_00_Q4_12 0x1000 +#define CNST_0_85_Q4_12 0x0D9B +#define CNST_0_4_Q4_12 0x0666 +#define CNST_0_05_Q4_12 0x00CD +#define CNST_0_5882_Q1_15 0x4B4B +#define CNST_0_2857_Q1_15 0x2492 + +#define CNST_0_5_Q1_15 0x4000 +#define CNST_0_5_Q5_11 0x0400 +#define CNST_1_0_Q1_15 0x7FFF + +// --------------------------------------------------------------------------- +// Macros +// --------------------------------------------------------------------------- + +#define HI_BYTE(a) ((a >> 8) & 0xFF) +#define LO_BYTE(a) (a & 0xFF); + +#endif // __IMBE_GLOBALS_H__ diff --git a/vocoder/imbe/imbe.h b/vocoder/imbe/imbe.h new file mode 100644 index 0000000..9897f96 --- /dev/null +++ b/vocoder/imbe/imbe.h @@ -0,0 +1,70 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ +#ifndef __IMBE_H__ +#define __IMBE_H__ + +#include "imbe/typedef.h" + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +#define FRAME 160 // Number samples in frame +#define NUM_HARMS_MAX 56 // Maximum number of harmonics +#define NUM_HARMS_MIN 9 // Minimum number of harmonics +#define NUM_BANDS_MAX 12 // Maximum number of bands +#define MAX_BLOCK_LEN 10 // Maximum length of block used during spectral amplitude encoding +#define NUM_PRED_RES_BLKS 6 // Number of Prediction Residual Blocks +#define PE_LPF_ORD 21 // Order of Pitch estimation LPF +#define PITCH_EST_FRAME 301 // Pitch estimation frame size + +#define B_NUM (NUM_HARMS_MAX - 1) + +#define FFTLENGTH 256 + +#define PITCH_EST_BUF_SIZE 621 + +// --------------------------------------------------------------------------- +// Types +// --------------------------------------------------------------------------- + +typedef struct { + Word16 e_p; + Word16 pitch; // Q14.2 + Word16 ref_pitch; // Q8.8 + Word32 fund_freq; + Word16 num_harms; + Word16 num_bands; + Word16 v_uv_dsn[NUM_HARMS_MAX]; + Word16 b_vec[NUM_HARMS_MAX + 3]; + Word16 bit_alloc[B_NUM + 4]; + Word16 sa[NUM_HARMS_MAX]; + Word16 l_uv; + Word16 div_one_by_num_harm; + Word16 div_one_by_num_harm_sh; +} IMBE_PARAM; + +typedef struct { + Word16 re; + Word16 im; +} Cmplx16; + +#endif // __IMBE_H__ diff --git a/vocoder/imbe/imbe_vocoder.cpp b/vocoder/imbe/imbe_vocoder.cpp new file mode 100644 index 0000000..0e4b3e1 --- /dev/null +++ b/vocoder/imbe/imbe_vocoder.cpp @@ -0,0 +1,63 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include +#include + +#include "imbe/imbe_vocoder.h" + +// --------------------------------------------------------------------------- +// Public Class Members +// --------------------------------------------------------------------------- + +imbe_vocoder::imbe_vocoder(void) : + prev_pitch(0), + prev_prev_pitch(0), + prev_e_p(0), + prev_prev_e_p(0), + seed(1), + num_harms_prev1(0), + num_harms_prev2(0), + num_harms_prev3(0), + fund_freq_prev(0), + th_max(0), + dc_rmv_mem(0), + d_gain_adjust(0) +{ + memset(wr_array, 0, sizeof(wr_array)); + memset(wi_array, 0, sizeof(wi_array)); + memset(pitch_est_buf, 0, sizeof(pitch_est_buf)); + memset(pitch_ref_buf, 0, sizeof(pitch_ref_buf)); + memset(pe_lpf_mem, 0, sizeof(pe_lpf_mem)); + memset(fft_buf, 0, sizeof(fft_buf)); + memset(sa_prev1, 0, sizeof(sa_prev1)); + memset(sa_prev2, 0, sizeof(sa_prev2)); + memset(uv_mem, 0, sizeof(uv_mem)); + memset(ph_mem, 0, sizeof(ph_mem)); + memset(vu_dsn_prev, 0, sizeof(vu_dsn_prev)); + memset(sa_prev3, 0, sizeof(sa_prev3)); + memset(v_uv_dsn, 0, sizeof(v_uv_dsn)); + + memset(&my_imbe_param, 0, sizeof(IMBE_PARAM)); + + decode_init(&my_imbe_param); + encode_init(); +} diff --git a/vocoder/imbe/imbe_vocoder.h b/vocoder/imbe/imbe_vocoder.h new file mode 100644 index 0000000..56075b3 --- /dev/null +++ b/vocoder/imbe/imbe_vocoder.h @@ -0,0 +1,117 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ +#ifndef __IMBE_VOCODER_H__ +#define __IMBE_VOCODER_H__ + +#ifdef _MSC_VER +#pragma warning(disable : 4251) +#endif + +#include +#include + +#include "imbe/imbe.h" +#include "imbe/basic_op.h" +#include "imbe/math_sub.h" + +// --------------------------------------------------------------------------- +// Class Declaration +// +// --------------------------------------------------------------------------- + +class imbe_vocoder { +public: + imbe_vocoder(void); + ~imbe_vocoder() { } + + // imbe_encode compresses 160 samples (in unsigned int format) + // outputs u[] vectors as frame_vector[] + void imbe_encode(int16_t *frame_vector, int16_t *snd) + { + encode(&my_imbe_param, frame_vector, snd); + } + + // imbe_decode decodes IMBE codewords (frame_vector), + // outputs the resulting 160 audio samples (snd) + void imbe_decode(int16_t *frame_vector, int16_t *snd) + { + decode(&my_imbe_param, frame_vector, snd); + } + + // hack to enable ambe encoder read access to speech parameters + const IMBE_PARAM* param(void) { return &my_imbe_param; } + void set_gain_adjust(float gain_adjust) { d_gain_adjust = gain_adjust; } + +private: + IMBE_PARAM my_imbe_param; + + /* data items originally static (moved from individual c++ sources) */ + Word16 prev_pitch, prev_prev_pitch, prev_e_p, prev_prev_e_p; + UWord32 seed; + Word16 num_harms_prev1; + Word32 sa_prev1[NUM_HARMS_MAX + 2]; + Word16 num_harms_prev2; + Word32 sa_prev2[NUM_HARMS_MAX + 2]; + Word16 uv_mem[105]; + UWord32 ph_mem[NUM_HARMS_MAX]; + Word16 num_harms_prev3; + Word32 fund_freq_prev; + Word16 vu_dsn_prev[NUM_HARMS_MAX]; + Word16 sa_prev3[NUM_HARMS_MAX]; + Word32 th_max; + Word16 v_uv_dsn[NUM_BANDS_MAX]; + Word16 wr_array[FFTLENGTH / 2 + 1]; + Word16 wi_array[FFTLENGTH / 2 + 1]; + Word16 pitch_est_buf[PITCH_EST_BUF_SIZE]; + Word16 pitch_ref_buf[PITCH_EST_BUF_SIZE]; + Word32 dc_rmv_mem; + Cmplx16 fft_buf[FFTLENGTH]; + Word16 pe_lpf_mem[PE_LPF_ORD]; + float d_gain_adjust; + + /* member functions */ + void idct(Word16 *in, Word16 m_lim, Word16 i_lim, Word16 *out); + void dct(Word16 *in, Word16 m_lim, Word16 i_lim, Word16 *out); + void fft_init(void); + void fft(Word16 *datam1, Word16 nn, Word16 isign); + void encode(IMBE_PARAM *imbe_param, Word16 *frame_vector, Word16 *snd); + void pitch_est_init(void); + Word32 autocorr(Word16 *sigin, Word16 shift, Word16 scale_shift); + void e_p(Word16 *sigin, Word16 *res_buf); + void pitch_est(IMBE_PARAM *imbe_param, Word16 *frames_buf); + void sa_decode_init(void); + void sa_decode(IMBE_PARAM *imbe_param); + void sa_encode_init(void); + void sa_encode(IMBE_PARAM *imbe_param); + void uv_synt_init(void); + void uv_synt(IMBE_PARAM *imbe_param, Word16 *snd); + void v_synt_init(void); + void v_synt(IMBE_PARAM *imbe_param, Word16 *snd); + void pitch_ref_init(void); + Word16 voiced_sa_calc(Word32 num, Word16 den); + Word16 unvoiced_sa_calc(Word32 num, Word16 den); + void v_uv_det(IMBE_PARAM *imbe_param, Cmplx16 *fft_buf); + void decode_init(IMBE_PARAM *imbe_param); + void decode(IMBE_PARAM *imbe_param, Word16 *frame_vector, Word16 *snd); + void encode_init(void); +}; + +#endif // __IMBE_VOCODER_H__ diff --git a/vocoder/imbe/math_sub.cpp b/vocoder/imbe/math_sub.cpp new file mode 100644 index 0000000..9afd836 --- /dev/null +++ b/vocoder/imbe/math_sub.cpp @@ -0,0 +1,345 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/basic_op.h" +#include "imbe/math_sub.h" + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +// ----------------------------------------------------------------------------- +// Table for routine Pow2() table[] = 2^(-1...0) +// ----------------------------------------------------------------------------- +static const Word16 pow2_table[33] = +{ + 16384, 16743, 17109, 17484, 17867, 18258, 18658, 19066, 19484, 19911, + 20347, 20792, 21247, 21713, 22188, 22674, 23170, 23678, 24196, 24726, + 25268, 25821, 26386, 26964, 27554, 28158, 28774, 29405, 30048, 30706, + 31379, 32066, 32767 +}; + +//----------------------------------------------------------------------------- +// PURPOSE: +// Computes pow(2.0, x) +// +// INPUT: +// x - In signed Q10.22 format +// +// OUTPUT: +// None +// +// RETURN: +// Result in signed Q14.2 format +// +//----------------------------------------------------------------------------- +Word16 Pow2(Word32 x) +{ + Word16 exp, i, a, tmp; + Word32 L_x; + Word16 exponent, fraction; + + exponent = extract_h(L_shr(x, 6)); + if (exponent < 0) + exponent = add(exponent, 1); + fraction = extract_l(L_shr(L_sub(x, L_shl(L_deposit_l(exponent), 6 + 16)), 7)); + + if (x < 0) + fraction = negate(fraction); + + L_x = L_mult(fraction, 32); // L_x = fraction<<6 + i = extract_h(L_x); // Extract b10-b16 of fraction + L_x = L_shr(L_x, 1); + a = extract_l(L_x); // Extract b0-b9 of fraction + a = a & (Word16)0x7fff; + + L_x = L_deposit_h(pow2_table[i]); // table[i] << 16 + tmp = sub(pow2_table[i], pow2_table[i + 1]); // table[i] - table[i+1] + L_x = L_msu(L_x, tmp, a); // L_x -= tmp*a*2 + + if (x < 0) { + L_x = L_deposit_h(div_s(0x4000, extract_h(L_x))); // calculate 1/fraction + exponent = sub(exponent, 1); + } + + exp = sub(12, exponent); + L_x = L_shr_r(L_x, exp); + + return extract_h(L_x); +} + +//----------------------------------------------------------------------------- +// PURPOSE: +// Multiply a 32 bit number (L_var2) and a 16 bit +// number (var1) returning a 32 bit result. L_var2 +// is truncated to 31 bits prior to executing the +// multiply. +// +// INPUT: +// L_var2 - A Word32 input variable +// var1 - A Word16 input variable +// +// OUTPUT: +// None +// +// RETURN: +// A Word32 value +// +//----------------------------------------------------------------------------- +Word32 L_mpy_ls(Word32 L_var2, Word16 var1) +{ + Word32 L_varOut; + Word16 swtemp; + + swtemp = shr(extract_l(L_var2), 1); + swtemp = (Word16)32767 & (Word16)swtemp; + + L_varOut = L_mult(var1, swtemp); + L_varOut = L_shr(L_varOut, 15); + L_varOut = L_mac(L_varOut, var1, extract_h(L_var2)); + return (L_varOut); +} + +// ----------------------------------------------------------------------------- +// Table for routine cos_fxp() +// ----------------------------------------------------------------------------- +static const Word16 cos_table[129] = +{ + 32767, 32766, 32758, 32746, 32729, 32706, 32679, 32647, 32610, + 32568, 32522, 32470, 32413, 32352, 32286, 32214, 32138, 32058, + 31972, 31881, 31786, 31686, 31581, 31471, 31357, 31238, 31114, + 30986, 30853, 30715, 30572, 30425, 30274, 30118, 29957, 29792, + 29622, 29448, 29269, 29086, 28899, 28707, 28511, 28311, 28106, + 27897, 27684, 27467, 27246, 27020, 26791, 26557, 26320, 26078, + 25833, 25583, 25330, 25073, 24812, 24548, 24279, 24008, 23732, + 23453, 23170, 22884, 22595, 22302, 22006, 21706, 21403, 21097, + 20788, 20475, 20160, 19841, 19520, 19195, 18868, 18538, 18205, + 17869, 17531, 17190, 16846, 16500, 16151, 15800, 15447, 15091, + 14733, 14373, 14010, 13646, 13279, 12910, 12540, 12167, 11793, + 11417, 11039, 10660, 10279, 9896, 9512, 9127, 8740, 8351, + 7962, 7571, 7180, 6787, 6393, 5998, 5602, 5205, 4808, + 4410, 4011, 3612, 3212, 2811, 2411, 2009, 1608, 1206, + 804, 402, 0 +}; + +//----------------------------------------------------------------------------- +// PURPOSE: +// Computes the cosine of x whose value is expressed in radians/PI. +// +// INPUT: +// x - argument in Q1.15 +// +// OUTPUT: +// None +// +// RETURN: +// Result in Q1.15 +// +//----------------------------------------------------------------------------- +Word16 cos_fxp(Word16 x) +{ + Word16 tx, ty; + Word16 sign; + Word16 index1, index2; + Word16 m; + Word16 temp; + + sign = 0; + if (x < 0) + tx = negate(x); + else + tx = x; + + // if angle > pi/2, cos(angle) = -cos(pi-angle) + if (tx > X05_Q15) { + tx = sub(ONE_Q15, tx); + sign = -1; + } + // convert input to be within range 0-128 + index1 = shr(tx, 7); + index2 = add(index1, 1); + + if (index1 == 128) + return (Word16)0; + + m = sub(tx, shl(index1, 7)); + // convert decimal part to Q15 + m = shl(m, 8); + + temp = sub(cos_table[index2], cos_table[index1]); + temp = mult(m, temp); + ty = add(cos_table[index1], temp); + + if (sign) + return negate(ty); + else + return ty; +} + +//----------------------------------------------------------------------------- +// PURPOSE: +// Computes the sinus of x whose value is expressed in radians/PI. +// +// INPUT: +// x - argument in Q1.15 +// +// OUTPUT: +// None +// +// RETURN: +// Result in Q1.15 +// +//----------------------------------------------------------------------------- +Word16 sin_fxp(Word16 x) +{ + Word16 tx, ty; + Word16 sign; + + sign = 0; + if (x < 0) { + tx = negate(x); + sign = 1; + } + else + tx = x; + + if (tx > X05_Q15) + tx = sub(tx, X05_Q15); + else + tx = sub(X05_Q15, tx); + + ty = cos_fxp(tx); + + if (sign) + return negate(ty); + else + return ty; +} + +// ----------------------------------------------------------------------------- +// Table for routine sqrt_l_exp() +// table[] = sqrt((i+16)*2^-6) * 2^15, i.e. sqrt(x) scaled Q15 +// ----------------------------------------------------------------------------- +static const Word16 sqrt_table[49] = +{ + 16384, 16888, 17378, 17854, 18318, 18770, 19212, 19644, 20066, 20480, + 20886, 21283, 21674, 22058, 22435, 22806, 23170, 23530, 23884, 24232, + 24576, 24915, 25249, 25580, 25905, 26227, 26545, 26859, 27170, 27477, + 27780, 28081, 28378, 28672, 28963, 29251, 29537, 29819, 30099, 30377, + 30652, 30924, 31194, 31462, 31727, 31991, 32252, 32511, 32767 +}; + +//----------------------------------------------------------------------------- +// PURPOSE: +// Computes sqrt(L_x), where L_x is positive. +// +// INPUT: +// L_x - argument in Q1.31 +// *exp - pointer to save denormalization exponent +// OUTPUT: +// Right shift to be applied to result, Q16.0 +// +// RETURN: +// Result in Q1.31 +// Right shift should be applied to it! +// +//----------------------------------------------------------------------------- +Word32 sqrt_l_exp(Word32 L_x, Word16* exp) +{ + Word16 e, i, a, tmp; + Word32 L_y; + + if (L_x <= (Word32)0) { + *exp = 0; + return (Word32)0; + } + + e = norm_l(L_x) & 0xFFFE; // get next lower EVEN norm. exp + L_x = L_shl(L_x, e); // L_x is normalized to [0.25..1) + *exp = e >> 1; // return 2*exponent (or Q1) + + L_x = L_shr(L_x, 9); + i = extract_h(L_x); // Extract b25-b31, 16 <= i <= 63 because of normalization + L_x = L_shr(L_x, 1); + a = extract_l(L_x); // Extract b10-b24 + a = a & (Word16)0x7fff; + + i = sub(i, 16); // 0 <= i <= 47 + + L_y = L_deposit_h(sqrt_table[i]); // table[i] << 16 + tmp = sub(sqrt_table[i], sqrt_table[i + 1]); // table[i] - table[i+1]) + L_y = L_msu(L_y, tmp, a); // L_y -= tmp*a*2 + + return L_y; +} + +//----------------------------------------------------------------------------- +// Table for routine Log2() +//----------------------------------------------------------------------------- +static const Word16 log_table[33] = +{ + 0, 1455, 2866, 4236, 5568, 6863, 8124, 9352, 10549, 11716, + 12855, 13967, 15054, 16117, 17156, 18172, 19167, 20142, 21097, 22033, + 22951, 23852, 24735, 25603, 26455, 27291, 28113, 28922, 29716, 30497, + 31266, 32023, 32767 +}; + +//----------------------------------------------------------------------------- +// PURPOSE: +// Computes log2 of x +// +// INPUT: +// x - argument in Q14.2 +// +// OUTPUT: +// None +// +// RETURN: +// Result in Q10.22 +// +//----------------------------------------------------------------------------- +Word32 Log2(Word16 x) +{ + Word16 exp, i, a, tmp; + Word32 L_y; + + if (x <= (Word16)0) + return 0; + + exp = norm_s(x); + x = shl(x, exp); + + i = shr(x, 9); // Extract b15-b9 + a = shl(x & 0x1FF, 6); // Extract b8-b0 + i = sub(i, 32); + + L_y = L_deposit_h(log_table[i]); // table[i] << 16 + tmp = sub(log_table[i], log_table[i + 1]); // table[i] - table[i+1] + L_y = L_msu(L_y, tmp, a); // L_y -= tmp*a*2 + + L_y = L_shr(L_y, 9); + + exp = sub(12, exp); + L_y = L_add(L_y, L_deposit_h(shl(exp, 6))); + + return L_y; +} diff --git a/vocoder/imbe/math_sub.h b/vocoder/imbe/math_sub.h new file mode 100644 index 0000000..18152b1 --- /dev/null +++ b/vocoder/imbe/math_sub.h @@ -0,0 +1,136 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ +#ifndef __MATH_SUB_H__ +#define __MATH_SUB_H__ + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +#define X05_Q15 16384 // (0.5*(1<<15)) +#define ONE_Q15 32767 // ((1<<15)-1) + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// PURPOSE: +// Computes the cosine of x whose value is expressed in radians/PI. +// +// INPUT: +// x - argument in Q1.15 +// +// OUTPUT: +// None +// +// RETURN: +// Result in Q1.15 +// +//----------------------------------------------------------------------------- +Word16 cos_fxp(Word16 x); + +//----------------------------------------------------------------------------- +// PURPOSE: +// Computes the sinus of x whose value is expressed in radians/PI. +// +// INPUT: +// x - argument in Q1.15 +// +// OUTPUT: +// None +// +// RETURN: +// Result in Q1.15 +// +//----------------------------------------------------------------------------- +Word16 sin_fxp(Word16 x); + +//----------------------------------------------------------------------------- +// PURPOSE: +// Multiply a 32 bit number (L_var2) and a 16 bit +// number (var1) returning a 32 bit result. L_var2 +// is truncated to 31 bits prior to executing the +// multiply. +// +// INPUT: +// L_var2 - A Word32 input variable +// var1 - A Word16 input variable +// +// OUTPUT: +// None +// +// RETURN: +// A Word32 value +// +//----------------------------------------------------------------------------- +Word32 L_mpy_ls(Word32 L_var2, Word16 var1); + +//----------------------------------------------------------------------------- +// PURPOSE: +// Computes pow(2.0, x) +// +// INPUT: +// x - In signed Q10.22 format +// +// OUTPUT: +// None +// +// RETURN: +// Result in signed Q14.2 format +// +//----------------------------------------------------------------------------- +Word16 Pow2(Word32 x); + +//----------------------------------------------------------------------------- +// PURPOSE: +// Computes sqrt(L_x), where L_x is positive. +// +// INPUT: +// L_x - argument in Q1.31 +// *exp - pointer to save denormalization exponent +// OUTPUT: +// Right shift to be applied to result, Q16.0 +// +// RETURN: +// Result in Q1.31 +// Right shift should be applied to it! +// +//----------------------------------------------------------------------------- +Word32 sqrt_l_exp(Word32 L_x, Word16 *exp); + +//----------------------------------------------------------------------------- +// PURPOSE: +// Computes log2 of x +// +// INPUT: +// x - argument in Q14.2 +// +// OUTPUT: +// None +// +// RETURN: +// Result in Q10.22 +// +//----------------------------------------------------------------------------- +Word32 Log2(Word16 x); + +#endif // __MATH_SUB_H__ diff --git a/vocoder/imbe/pe_lpf.cpp b/vocoder/imbe/pe_lpf.cpp new file mode 100644 index 0000000..170c5b2 --- /dev/null +++ b/vocoder/imbe/pe_lpf.cpp @@ -0,0 +1,78 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/globals.h" +#include "imbe/imbe.h" +#include "imbe/aux_sub.h" +#include "imbe/basic_op.h" +#include "imbe/math_sub.h" +#include "imbe/pe_lpf.h" + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +static const Word16 lpf_coef[PE_LPF_ORD] = +{ + -94, -92, 185, 543, 288, -883, -1834, -495, 3891, 9141, 11512, + 9141, 3891, -495, -1834, -883, 288, 543, 185, -92, -94 +}; + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// PURPOSE: +// Low-pass filter for pitch estimator +// +// +// INPUT: +// *sigin - pointer to input signal buffer +// *sigout - pointer to output signal buffer +// *mem - pointer to filter's memory element +// len - number of input signal samples +// +// OUTPUT: +// None +// +// RETURN: +// Saved filter state in mem +// +//----------------------------------------------------------------------------- +void pe_lpf(Word16* sigin, Word16* sigout, Word16* mem, Word16 len) +{ + Word16 i; + Word32 L_sum; + + while (len--) { + for (i = 0; i < PE_LPF_ORD - 1; i++) + mem[i] = mem[i + 1]; + mem[PE_LPF_ORD - 1] = *sigin++; + + L_sum = 0; + for (i = 0; i < PE_LPF_ORD; i++) + L_sum = L_mac(L_sum, mem[i], lpf_coef[i]); + + *sigout++ = L_round(L_sum); + } +} diff --git a/vocoder/imbe/pe_lpf.h b/vocoder/imbe/pe_lpf.h new file mode 100644 index 0000000..35e83be --- /dev/null +++ b/vocoder/imbe/pe_lpf.h @@ -0,0 +1,48 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ +#ifndef __PE_LPF_H__ +#define __PE_LPF_H__ + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// PURPOSE: +// Low-pass filter for pitch estimator +// +// +// INPUT: +// *sigin - pointer to input signal buffer +// *sigout - pointer to output signal buffer +// *mem - pointer to filter's memory element +// len - number of input signal samples +// +// OUTPUT: +// None +// +// RETURN: +// Saved filter state in mem +// +//----------------------------------------------------------------------------- +void pe_lpf(Word16 *sigin, Word16 *sigout, Word16 *mem, Word16 len); + +#endif // __PE_LPF_H__ diff --git a/vocoder/imbe/pitch_est.cpp b/vocoder/imbe/pitch_est.cpp new file mode 100644 index 0000000..b467674 --- /dev/null +++ b/vocoder/imbe/pitch_est.cpp @@ -0,0 +1,330 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/globals.h" +#include "imbe/imbe.h" +#include "imbe/basic_op.h" +#include "imbe/aux_sub.h" +#include "imbe/math_sub.h" +#include "imbe/tbls.h" +#include "imbe/pitch_est.h" +#include "imbe/imbe_vocoder.h" + +#if defined(__GNUC__) || defined(__GNUG__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#endif + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +static const UWord16 min_max_tbl[203] = +{ + 0x0008, 0x0009, 0x000a, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0012, 0x0013, + 0x0014, 0x0115, 0x0216, 0x0218, 0x0319, 0x041a, 0x051b, 0x061c, 0x061e, 0x071f, + 0x0820, 0x0921, 0x0a22, 0x0a24, 0x0b25, 0x0c26, 0x0d27, 0x0e28, 0x0e2a, 0x0f2b, + 0x102c, 0x112d, 0x122e, 0x1230, 0x1331, 0x1432, 0x1533, 0x1634, 0x1636, 0x1737, + 0x1838, 0x1939, 0x1a3a, 0x1a3c, 0x1b3d, 0x1c3e, 0x1d3f, 0x1e40, 0x1e42, 0x1f43, + 0x2044, 0x2145, 0x2246, 0x2248, 0x2349, 0x244a, 0x254b, 0x264c, 0x264e, 0x274f, + 0x2850, 0x2951, 0x2a52, 0x2a54, 0x2b55, 0x2c56, 0x2d57, 0x2e58, 0x2e5a, 0x2f5b, + 0x305c, 0x315d, 0x325e, 0x3260, 0x3361, 0x3462, 0x3563, 0x3664, 0x3666, 0x3767, + 0x3868, 0x3969, 0x3a6a, 0x3a6c, 0x3b6d, 0x3c6e, 0x3d6f, 0x3e70, 0x3e72, 0x3f73, + 0x4074, 0x4175, 0x4276, 0x4278, 0x4379, 0x447a, 0x457b, 0x467c, 0x467e, 0x477f, + 0x4880, 0x4981, 0x4a82, 0x4a84, 0x4b85, 0x4c86, 0x4d87, 0x4e88, 0x4e8a, 0x4f8b, + 0x508c, 0x518d, 0x528e, 0x5290, 0x5391, 0x5492, 0x5593, 0x5694, 0x5696, 0x5797, + 0x5898, 0x5999, 0x5a9a, 0x5a9c, 0x5b9d, 0x5c9e, 0x5d9f, 0x5ea0, 0x5ea2, 0x5fa3, + 0x60a4, 0x61a5, 0x62a6, 0x62a8, 0x63a9, 0x64aa, 0x65ab, 0x66ac, 0x66ae, 0x67af, + 0x68b0, 0x69b1, 0x6ab2, 0x6ab4, 0x6bb5, 0x6cb6, 0x6db7, 0x6eb8, 0x6eba, 0x6fbb, + 0x70bc, 0x71bd, 0x72be, 0x72c0, 0x73c1, 0x74c2, 0x75c3, 0x76c4, 0x76c6, 0x77c7, + 0x78c8, 0x79c9, 0x7aca, 0x7aca, 0x7bca, 0x7cca, 0x7dca, 0x7eca, 0x7eca, 0x7fca, + 0x80ca, 0x81ca, 0x82ca, 0x82ca, 0x83ca, 0x84ca, 0x85ca, 0x86ca, 0x86ca, 0x87ca, + 0x88ca, 0x89ca, 0x8aca, 0x8aca, 0x8bca, 0x8cca, 0x8dca, 0x8eca, 0x8eca, 0x8fca, + 0x90ca, 0x91ca, 0x92ca, 0x92ca, 0x93ca, 0x94ca, 0x95ca, 0x96ca, 0x96ca, 0x97ca, + 0x98ca, 0x99ca, 0x9aca +}; + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- + +void imbe_vocoder::pitch_est_init(void) +{ + prev_pitch = prev_prev_pitch = 158; // 100 + prev_e_p = prev_prev_e_p = 0; +} + +Word32 imbe_vocoder::autocorr(Word16* sigin, Word16 shift, Word16 scale_shift) +{ + Word32 L_sum; + Word16 i; + + L_sum = 0; + for (i = 0; i < PITCH_EST_FRAME - shift; i++) + L_sum = L_add(L_sum, L_shr(L_mult(sigin[i], sigin[i + shift]), scale_shift)); + + return L_sum; +} + +void imbe_vocoder::e_p(Word16* sigin, Word16* res_buf) +{ + Word16 i, j, den_part_acc, tmp; + Word32 L_sum, L_num, L_den, L_e0, L_tmp; + Word16 sig_wndwed[PITCH_EST_FRAME]; + Word32 corr[259]; + Word16 index_beg, index_step; + Word16 scale_shift; + + + // Windowing input signal s * wi^2 + for (i = 0; i < PITCH_EST_FRAME; i++) + sig_wndwed[i] = mult_r(sigin[i], wi[i]); + + L_sum = 0; + for (i = 0; i < PITCH_EST_FRAME; i++) + L_sum = L_add(L_sum, L_mpy_ls(L_mult(sigin[i], sigin[i]), wi[i])); // sum(s^2 * wi^2) + + // Check for the overflow + if (L_sum == MAX_32) { + // Recalculate with scaling + L_sum = 0; + for (i = 0; i < PITCH_EST_FRAME; i++) + L_sum = L_add(L_sum, L_mpy_ls(L_shr(L_mult(sigin[i], sigin[i]), 5), wi[i])); + scale_shift = 5; + } + else + scale_shift = 0; + + L_e0 = 0; + for (i = 0; i < PITCH_EST_FRAME; i++) + L_e0 = L_add(L_e0, L_shr(L_mult(sig_wndwed[i], sig_wndwed[i]), scale_shift)); // sum(s^2 * wi^4) + + // Calculate correlation for time shift in range 21...150 with step 0.5 + // For integer shifts + for (tmp = 21, i = 0; tmp <= 150; tmp++, i += 2) + corr[i] = autocorr(sig_wndwed, tmp, scale_shift); + // For intermediate shifts + for (i = 1; i < 258; i += 2) + corr[i] = L_shr(L_add(corr[i - 1], corr[i + 1]), 1); + + + // variable to calculate 1 - P * sum(wi ^4) in denominator + den_part_acc = CNST_0_8717_Q1_15; + + index_step = 42; // Note: 42 = 21 in Q15.1 format, so index_step will be used also as p in Q15.1 format + index_beg = 0; + L_e0 = L_shr(L_e0, 7); // divide by 64 to compensate wi scaling + // p = 21...122 by step 0.5 + for (i = 0; i < 203; i++) { + + // Calculate sum( corr ( n * p) ) + L_tmp = 0; + j = index_beg; + while (j <= 258) { + L_tmp = L_add(L_tmp, corr[j]); + j += index_step; + } + + L_tmp = L_shr(L_tmp, 6); // compensate wi scaling + L_tmp = L_add(L_tmp, L_e0); // For n = 0 + L_tmp = L_tmp * index_step; + L_num = L_sub(L_sum, L_tmp); + + index_beg++; + index_step++; + + L_den = L_mpy_ls(L_sum, den_part_acc); + + if (L_num < L_den && L_den != 0) { + //res_buf[i] = (Word16)((double)L_num/(double)L_den * 4096.); // Q4.12 + + if (L_num <= 0) + res_buf[i] = 0; + else { + tmp = norm_l(L_den); + tmp = div_s(extract_h(L_shl(L_num, tmp)), extract_h(L_shl(L_den, tmp))); + res_buf[i] = shr(tmp, 3); // convert to Q4.12 + } + } + else if (L_num >= L_den) { + res_buf[i] = CNST_1_00_Q4_12; + //res_buf[i] = (Word16)((double)L_num/(double)L_den * 4096.); // Q4.12 + } + else + res_buf[i] = CNST_1_00_Q4_12; + + den_part_acc = sub(den_part_acc, CNST_0_0031_Q1_15); + } +} + +void imbe_vocoder::pitch_est(IMBE_PARAM* imbe_param, Word16* frames_buf) +{ + Word16 e_p_arr0[203], e_p_arr1[203], e_p_arr2[203], e1p1_e2p2_est_save[203]; + Word16 min_index, max_index, p, i, p_index; + UWord16 tmp = 0, p_fp; + UWord32 UL_tmp; + Word16 e_p_cur, pb, pf, ceb, s_tmp; + Word16 cef_est, cef, p0_est, p0, p1, p2, p1_max_index, p2_max_index, e1p1_e2p2_est, e1p1_e2p2; + Word16 e_p_arr2_min[203]; + + // Calculate E(p) function for current and two future frames + e_p(&frames_buf[0], e_p_arr0); + + // Look-Back Pitch Tracking + min_index = HI_BYTE(min_max_tbl[prev_pitch]); + max_index = LO_BYTE(min_max_tbl[prev_pitch]); + + p = pb = min_index; + e_p_cur = e_p_arr0[min_index]; + while (++p <= max_index) + if (e_p_arr0[p] < e_p_cur) { + e_p_cur = e_p_arr0[p]; + pb = p; + } + ceb = add(e_p_cur, add(prev_e_p, prev_prev_e_p)); + + + if (ceb <= CNST_0_48_Q4_12) { + prev_prev_pitch = prev_pitch; + prev_pitch = pb; + prev_prev_e_p = prev_e_p; + prev_e_p = e_p_arr0[pb]; + + imbe_param->pitch = pb + 42; // Result in Q15.1 format + imbe_param->e_p = prev_e_p; + return; + } + + + // Look-Ahead Pitch Tracking + e_p(&frames_buf[FRAME], e_p_arr1); + e_p(&frames_buf[2 * FRAME], e_p_arr2); + + p0_est = p0 = 0; + cef_est = e_p_arr0[p0] + e_p_arr1[p0] + e_p_arr2[p0]; + e1p1_e2p2 = 1; + + p1 = 0; + while (p1 < 203) { + p2 = HI_BYTE(min_max_tbl[p1]); + p2_max_index = LO_BYTE(min_max_tbl[p1]); + s_tmp = e_p_arr2[p1]; + while (p2 <= p2_max_index) { + if (e_p_arr2[p2] < s_tmp) + s_tmp = e_p_arr2[p2]; + p2++; + } + e_p_arr2_min[p1] = s_tmp; + p1++; + } + while (p0 < 203) { + e1p1_e2p2_est = e_p_arr1[p0] + e_p_arr2_min[p0]; + p1 = HI_BYTE(min_max_tbl[p0]); + p1_max_index = LO_BYTE(min_max_tbl[p0]); + while (p1 <= p1_max_index) { + if (add(e_p_arr1[p1], e_p_arr2_min[p1]) < e1p1_e2p2_est) + e1p1_e2p2_est = add(e_p_arr1[p1], e_p_arr2_min[p1]); + p1++; + } + e1p1_e2p2_est_save[p0] = e1p1_e2p2_est; + cef = add(e_p_arr0[p0], e1p1_e2p2_est); + if (cef < cef_est) { + cef_est = cef; + p0_est = p0; + } + p0++; + } + + pf = p0_est; + // Sub-multiples analysis + if (pf >= 42) // Check if Sub-multiples are possible + { + if (pf < 84) + i = 1; + else if (pf < 126) + i = 2; + else if (pf < 168) + i = 3; + else + i = 4; + + p_fp = (pf + 42) << 8; // Convert pitch estimation from array index to unsigned Q7.19 format + + while (i--) { + switch (i) { + case 0: + tmp = p_fp >> 1; // P_est/2 + break; + + case 1: + UL_tmp = (UWord32)p_fp * 0x5555; // P_est/3 + tmp = UL_tmp >> 16; + break; + + case 2: + tmp = p_fp >> 2; // P_est/4 + break; + + case 3: + UL_tmp = (UWord32)p_fp * 0x3333; // P_est/5 + tmp = UL_tmp >> 16; + break; + } + + p_index = ((tmp + 0x0080) >> 8) - 42; // Convert fixed-point pitch value to integer array index with rounding + + cef = add(e_p_arr0[p_index], e1p1_e2p2_est_save[p_index]); + + if (cef <= CNST_0_85_Q4_12 && mult_r(cef, CNST_0_5882_Q1_15) <= cef_est) // 1/1.7 = 0.5882 + { + pf = p_index; + break; + } + + if (cef <= CNST_0_4_Q4_12 && mult_r(cef, CNST_0_2857_Q1_15) <= cef_est) // 1/3.5 = 0.2857 + { + pf = p_index; + break; + } + + if (cef <= CNST_0_05_Q4_12) { + pf = p_index; + break; + } + } + } + + cef = add(e_p_arr0[pf], e1p1_e2p2_est_save[pf]); + + if (ceb <= cef) + p = pb; + else + p = pf; + + prev_prev_pitch = prev_pitch; + prev_pitch = p; + prev_prev_e_p = prev_e_p; + prev_e_p = e_p_arr0[p]; + + + imbe_param->pitch = p + 42; // Result in Q15.1 format + imbe_param->e_p = prev_e_p; +} diff --git a/vocoder/imbe/pitch_est.h b/vocoder/imbe/pitch_est.h new file mode 100644 index 0000000..9037d32 --- /dev/null +++ b/vocoder/imbe/pitch_est.h @@ -0,0 +1,31 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ +#ifndef __PITCH_EST__ +#define __PITCH_EST__ + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +void pitch_est_init(void); +void pitch_est(IMBE_PARAM *imbe_param, Word16 *frames_buf); + +#endif // __PITCH_EST__ diff --git a/vocoder/imbe/pitch_ref.cpp b/vocoder/imbe/pitch_ref.cpp new file mode 100644 index 0000000..283d087 --- /dev/null +++ b/vocoder/imbe/pitch_ref.cpp @@ -0,0 +1,159 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/globals.h" +#include "imbe/imbe.h" +#include "imbe/basic_op.h" +#include "imbe/aux_sub.h" +#include "imbe/math_sub.h" +#include "imbe/tbls.h" +#include "imbe/pitch_ref.h" + +#include +#include +#include + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +#define PITCH_REF_FRAME 221 +#define MIN_INDEX 50 + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +void pitch_ref(IMBE_PARAM* imbe_param, Cmplx16* fft_buf) +{ + Word16 i, j, index_a_save, pitch_est, tmp, shift, index_wr, up_lim; + Cmplx16 sp_rec[FFTLENGTH / 2]; + Word32 fund_freq, fund_freq_2, fund_freq_acc_a, fund_freq_acc_b, fund_freq_acc, L_tmp, amp_re_acc, amp_im_acc, L_sum, L_diff_min; + Word16 ha, hb, index_a, index_b, index_tbl[20], it_ind, re_tmp, im_tmp, pitch_cand = 0; + Word32 fund_freq_cand = 0; + + + pitch_est = shl(imbe_param->pitch, 7); // Convert to Q8.8 + pitch_est = sub(pitch_est, CNST_1_125_Q8_8); // Sub 1.125 = 9/8 + + L_diff_min = MAX_32; + for (i = 0; i < 19; i++) + { + shift = norm_s(pitch_est); + tmp = shl(pitch_est, shift); + tmp = div_s(0x4000, tmp); + fund_freq = L_shl(tmp, shift + 11); + + fund_freq_acc = fund_freq; + fund_freq_2 = L_shr(fund_freq, 1); + fund_freq_acc_a = L_sub(fund_freq, fund_freq_2); + fund_freq_acc_b = L_add(fund_freq, fund_freq_2); + + // Calculate upper limit for spectrum reconstruction + up_lim = extract_h(L_shr((UWord32)CNST_0_9254_Q0_16 * pitch_est, 1)); // 0.9254/fund_freq + up_lim = sub(up_lim, CNST_0_5_Q8_8); // sub 0.5 + up_lim = up_lim & 0xFF00; // extract fixed part + up_lim = mult(up_lim, extract_h(fund_freq)); + up_lim = shr(up_lim, 1); + + index_b = 0; + while (index_b <= up_lim) + { + ha = extract_h(fund_freq_acc_a); + hb = extract_h(fund_freq_acc_b); + index_a = (ha >> 8) + ((ha & 0xFF) ? 1 : 0); + index_b = (hb >> 8) + ((hb & 0xFF) ? 1 : 0); + + if (index_b >= MIN_INDEX) + { + L_tmp = L_shl(L_deposit_h(index_a), 8); + L_tmp = L_sub(L_tmp, fund_freq_acc); + L_tmp = L_add(L_tmp, 0x00020000); // for rounding purpose + L_tmp = L_shr(L_tmp, 2); + + index_a_save = index_a; + it_ind = 0; + + amp_re_acc = amp_im_acc = 0; + while (index_a < index_b) + { + index_wr = extract_h(L_tmp); + if (index_wr < 0 && (L_tmp & 0xFFFF)) // truncating for negative number + index_wr = add(index_wr, 1); + index_wr = add(index_wr, 160); + index_tbl[it_ind++] = index_wr; + if (index_wr >= 0 && index_wr <= 320) + { + amp_re_acc = L_mac(amp_re_acc, fft_buf[index_a].re, wr_sp[index_wr]); + amp_im_acc = L_mac(amp_im_acc, fft_buf[index_a].im, wr_sp[index_wr]); + } + + index_a++; + L_tmp = L_add(L_tmp, 0x400000); + } + + it_ind = 0; + index_a = index_a_save; + while (index_a < index_b) + { + index_wr = index_tbl[it_ind++]; + if (index_wr < 0 || index_wr > 320) + { + sp_rec[index_a].im = sp_rec[index_a].re = 0; + } + else + { + sp_rec[index_a].im = mult(mult(extract_h(amp_im_acc), wr_sp[index_wr]), 0x6666); + sp_rec[index_a].re = mult(mult(extract_h(amp_re_acc), wr_sp[index_wr]), 0x6666); + } + + index_a++; + } + } + + fund_freq_acc_a = L_add(fund_freq_acc_a, fund_freq); + fund_freq_acc_b = L_add(fund_freq_acc_b, fund_freq); + fund_freq_acc = L_add(fund_freq_acc, fund_freq); + } + + L_sum = 0; + for (j = MIN_INDEX; j <= up_lim; j++) + { + re_tmp = sub(fft_buf[j].re, sp_rec[j].re); + im_tmp = sub(fft_buf[j].im, sp_rec[j].im); + L_sum = L_mac(L_sum, re_tmp, re_tmp); + L_sum = L_mac(L_sum, im_tmp, im_tmp); + } + + if (L_sum < L_diff_min) + { + L_diff_min = L_sum; + pitch_cand = pitch_est; + fund_freq_cand = fund_freq; + } + + pitch_est = add(pitch_est, CNST_0_125_Q8_8); // Add 0.125 = 1/8 + } + + imbe_param->ref_pitch = pitch_cand; + imbe_param->fund_freq = fund_freq_cand; +} diff --git a/vocoder/imbe/pitch_ref.h b/vocoder/imbe/pitch_ref.h new file mode 100644 index 0000000..2953ffb --- /dev/null +++ b/vocoder/imbe/pitch_ref.h @@ -0,0 +1,30 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ +#ifndef __PITCH_REF_H__ +#define __PITCH_REF_H__ + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +void pitch_ref(IMBE_PARAM *imbe_param, Cmplx16 *fft_buf); + +#endif // __PITCH_REF_H__ diff --git a/vocoder/imbe/qnt_sub.cpp b/vocoder/imbe/qnt_sub.cpp new file mode 100644 index 0000000..e6745c0 --- /dev/null +++ b/vocoder/imbe/qnt_sub.cpp @@ -0,0 +1,143 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/basic_op.h" +#include "imbe/qnt_sub.h" + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// PURPOSE: +// Dequantize by quantizer step size +// +// +// INPUT: +// qval - quantized value +// step_size - step size used to quantize in unsigned Q0.16 format +// bit_num - the number of bits +// +// OUTPUT: +// None +// +// RETURN: +// Quantized Value in signed (bit_num).16 format +// +//----------------------------------------------------------------------------- +Word32 deqnt_by_step(Word16 qval, UWord16 step_size, Word16 bit_num) +{ + Word32 res; + + if (bit_num == 0) + return (Word32)0; + + res = (Word32)step_size * (qval - (1 << (bit_num - 1))); + res = L_add(res, ((Word32)step_size * CNST_0_5_Q0_16) >> 16); + + return res; +} + +//----------------------------------------------------------------------------- +// PURPOSE: +// Quantize by quantizer step size +// +// +// INPUT: +// val - value to be quantized in Q5.10 format +// step_size - step size used to quantize in unsigned Q0.16 format +// bit_num - the number of bits +// +// OUTPUT: +// None +// +// RETURN: +// Quantized Value in integer +// +//----------------------------------------------------------------------------- +Word16 qnt_by_step(Word16 val, UWord16 step_size, Word16 bit_num) +{ + Word16 index, min_val, max_val; + Word16 q_index, shift, tmp; + + shift = norm_s(step_size); + + tmp = div_s(0x4000, shl(step_size, shift)); // Remark: To get result in Qxx.16 format it is necessary left shift tmp by (shift + 3) + q_index = shr_r(mult(val, tmp), sub(9, shift)); // q_index here is rounded to the nearest integer + + max_val = 1 << (bit_num - 1); + min_val = negate(max_val); + + if (q_index < min_val) + index = 0; + else if (q_index >= max_val) + index = (1 << bit_num) - 1; + else + index = max_val + q_index; + + return index; +} + +//----------------------------------------------------------------------------- +// PURPOSE: +// Quantize by table +// +// +// INPUT: +// val - value to be quantized +// q_tbl - pointer to table +// q_tbl_size - size of table +// +// OUTPUT: +// None +// +// RETURN: +// Quantized Value in integer +// +//----------------------------------------------------------------------------- +Word16 tbl_quant(Word16 val, Word16* q_tbl, Word16 q_tbl_size) +{ + Word16 min_index, max_index, index; + + min_index = 0; + max_index = q_tbl_size - 1; + + if (val >= q_tbl[max_index]) + return max_index; + + if (val <= q_tbl[min_index]) + return min_index; + + while (max_index - min_index != 1) { + index = min_index + ((max_index - min_index) >> 1); + + if (q_tbl[index] > val) + max_index = index; + else + min_index = index; + } + + if (q_tbl[max_index] - val <= val - q_tbl[min_index]) + return max_index; + else + return min_index; +} diff --git a/vocoder/imbe/qnt_sub.h b/vocoder/imbe/qnt_sub.h new file mode 100644 index 0000000..04dc3b0 --- /dev/null +++ b/vocoder/imbe/qnt_sub.h @@ -0,0 +1,91 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ +#ifndef __QNT_SUB_H__ +#define __QNT_SUB_H__ + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +#define CNST_0_5_Q0_16 0x8000 + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// PURPOSE: +// Dequantize by quantizer step size +// +// +// INPUT: +// qval - quantized value +// step_size - step size used to quantize in unsigned Q0.16 format +// bit_num - the number of bits +// +// OUTPUT: +// None +// +// RETURN: +// Quantized Value in signed (bit_num).16 format +// +//----------------------------------------------------------------------------- +Word32 deqnt_by_step(Word16 qval, UWord16 step_size, Word16 bit_num); + +//----------------------------------------------------------------------------- +// PURPOSE: +// Quantize by quantizer step size +// +// +// INPUT: +// val - value to be quantized +// step_size - step size used to quantize in unsigned Q0.16 format +// bit_num - the number of bits +// +// OUTPUT: +// None +// +// RETURN: +// Quantized Value in integer +// +//----------------------------------------------------------------------------- +Word16 qnt_by_step(Word16 val, UWord16 step_size, Word16 bit_num); + +//----------------------------------------------------------------------------- +// PURPOSE: +// Quantize by table +// +// +// INPUT: +// val - value to be quantized +// q_tbl - pointer to table +// q_tbl_size - size of table +// +// OUTPUT: +// None +// +// RETURN: +// Quantized Value in integer +// +//----------------------------------------------------------------------------- +Word16 tbl_quant(Word16 val, Word16 *q_tbl, Word16 q_tbl_size); + +#endif // __QNT_SUB_H__ diff --git a/vocoder/imbe/rand_gen.cpp b/vocoder/imbe/rand_gen.cpp new file mode 100644 index 0000000..87bcf6e --- /dev/null +++ b/vocoder/imbe/rand_gen.cpp @@ -0,0 +1,66 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/basic_op.h" + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +static UWord32 seed = 1; + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// PURPOSE: +// Generate pseudo-random numbers in range -1...1 +// +// +// INPUT: +// None +// +// OUTPUT: +// None +// +// RETURN: +// Pseudo-random number in signed Q1.16 format +// +//----------------------------------------------------------------------------- +Word16 rand_gen(void) +{ + UWord32 hi, lo; + + lo = 16807 * (seed & 0xFFFF); + hi = 16807 * (seed >> 16); + + lo += (Word32)(hi & 0x7FFF) << 16; + lo += (hi >> 15); + + if (lo > 0x7FFFFFFF) + lo -= 0x7FFFFFFF; + + seed = lo; + + return (Word16)lo; +} diff --git a/vocoder/imbe/rand_gen.h b/vocoder/imbe/rand_gen.h new file mode 100644 index 0000000..c94cff2 --- /dev/null +++ b/vocoder/imbe/rand_gen.h @@ -0,0 +1,45 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ +#ifndef __RAND_GEN_H__ +#define __RAND_GEN_H__ + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// PURPOSE: +// Generate pseudo-random numbers in range -1...1 +// +// +// INPUT: +// None +// +// OUTPUT: +// None +// +// RETURN: +// Pseudo-random number in signed Q1.16 format +// +//----------------------------------------------------------------------------- +Word16 rand_gen(void); + +#endif // __RAND_GEN_H__ diff --git a/vocoder/imbe/sa_decode.cpp b/vocoder/imbe/sa_decode.cpp new file mode 100644 index 0000000..f0c6f41 --- /dev/null +++ b/vocoder/imbe/sa_decode.cpp @@ -0,0 +1,187 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/globals.h" +#include "imbe/basic_op.h" +#include "imbe/imbe.h" +#include "imbe/tbls.h" +#include "imbe/qnt_sub.h" +#include "imbe/aux_sub.h" +#include "imbe/math_sub.h" +#include "imbe/imbe_vocoder.h" + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// PURPOSE: +// Initialization of Spectral Amplitude Decoder +// +// +// INPUT: +// None +// +// OUTPUT: +// None +// +// RETURN: +// None +// +//----------------------------------------------------------------------------- +void imbe_vocoder::sa_decode_init(void) +{ + num_harms_prev1 = 30; + v_zap((Word16*)sa_prev1, 2 * (NUM_HARMS_MAX + 2)); +} + +//----------------------------------------------------------------------------- +// PURPOSE: +// Perform Spectral Amplitude Decoding +// +// +// INPUT: +// IMBE_PARAM *imbe_param - pointer to IMBE_PARAM structure with +// valid num_harms and b_vec items +// +// OUTPUT: +// None +// +// RETURN: +// Decoded Spectral Amplitudes +// +//----------------------------------------------------------------------------- +void imbe_vocoder::sa_decode(IMBE_PARAM* imbe_param) +{ + Word16 gain_vec[6], gain_r[6]; + UWord16 index, index_1, num_harms; + Word16* gss_ptr, *ba_ptr, i, j, *t_vec_ptr, *b_vec_ptr; + Word16 t_vec[NUM_HARMS_MAX], c_vec[MAX_BLOCK_LEN]; + Word32 lmprbl_item; + Word16 bl_len, step_size, num_bits, tmp, ro_coef, si_coef, tmp1; + UWord32 k_coef, k_acc; + Word32 sum, tmp_word32, sa_tmp[NUM_HARMS_MAX]; + Word16* sa; + + num_harms = imbe_param->num_harms; + index = num_harms - NUM_HARMS_MIN; + ba_ptr = imbe_param->bit_alloc; + b_vec_ptr = &imbe_param->b_vec[2]; + sa = imbe_param->sa; + + // Decoding the Gain Vector. gain_vec has signed Q5.11 format + gss_ptr = (Word16*)&gain_step_size_tbl[index * 5]; + gain_vec[0] = gain_qnt_tbl[*b_vec_ptr++]; + + for (i = 1; i < 6; i++) + gain_vec[i] = extract_l(L_shr(deqnt_by_step(*b_vec_ptr++, *gss_ptr++, *ba_ptr++), 5)); + idct(gain_vec, NUM_PRED_RES_BLKS, NUM_PRED_RES_BLKS, gain_r); + + lmprbl_item = lmprbl_tbl[index]; + v_zap(t_vec, NUM_HARMS_MAX); + + // Decoding the Higher Order DCT Coefficients + t_vec_ptr = t_vec; + for (i = 0; i < NUM_PRED_RES_BLKS; i++) { + bl_len = (lmprbl_item >> 28) & 0xF; lmprbl_item <<= 4; + v_zap(c_vec, MAX_BLOCK_LEN); + c_vec[0] = gain_r[i]; + for (j = 1; j < bl_len; j++) { + num_bits = *ba_ptr++; + if (num_bits) { + step_size = extract_h(((Word32)hi_ord_std_tbl[j - 1] * hi_ord_step_size_tbl[num_bits - 1]) << 1); + c_vec[j] = extract_l(L_shr(deqnt_by_step(*b_vec_ptr, step_size, num_bits), 5)); + } + else + c_vec[j] = 0; + + b_vec_ptr++; + } + idct(c_vec, bl_len, bl_len, t_vec_ptr); + t_vec_ptr += bl_len; + } + + // Calculate num_harms_prev/num_harms. Result save in unsigned format Q8.24 + if (num_harms == num_harms_prev1) + k_coef = (Word32)CNST_ONE_Q8_24; + else if (num_harms > num_harms_prev1) + k_coef = (Word32)div_s(num_harms_prev1 << 9, num_harms << 9) << 9; + else { + // imbe_param->num_harms < num_harms_prev1 + k_coef = 0; + tmp = num_harms_prev1; + while (tmp > num_harms) { + tmp -= num_harms; + k_coef += (Word32)CNST_ONE_Q8_24; + } + k_coef += (Word32)div_s(tmp << 9, num_harms << 9) << 9; + } + + if (num_harms <= 15) + ro_coef = CNST_0_4_Q1_15; + else if (num_harms <= 24) + ro_coef = num_harms * CNST_0_03_Q1_15 - CNST_0_05_Q1_15; + else + ro_coef = CNST_0_7_Q1_15; + + k_acc = k_coef; + sum = 0; + + for (i = num_harms_prev1 + 1; i < NUM_HARMS_MAX + 2; i++) + sa_prev1[i] = sa_prev1[num_harms_prev1]; + + for (i = 0; i < num_harms; i++) { + index = (UWord16)(k_acc >> 24); // Get integer part + si_coef = (Word16)((k_acc - ((UWord32)index << 24)) >> 9); // Get fractional part + + if (si_coef == 0) { + tmp_word32 = L_mpy_ls(sa_prev1[index], ro_coef); // sa_prev1 here is in Q10.22 format + sa_tmp[i] = L_add(L_shr(L_deposit_h(t_vec[i]), 5), tmp_word32); // Convert t_vec to Q10.22 and add ... + sum = L_add(sum, sa_prev1[index]); // sum in Q10.22 format + } + else { + index_1 = index + 1; + tmp_word32 = L_mpy_ls(sa_prev1[index], sub(0x7FFF, si_coef)); + sum = L_add(sum, tmp_word32); + sa_tmp[i] = L_add(L_shr(L_deposit_h(t_vec[i]), 5), L_mpy_ls(tmp_word32, ro_coef)); + + tmp_word32 = L_mpy_ls(sa_prev1[index_1], si_coef); + sum = L_add(sum, tmp_word32); + sa_tmp[i] = L_add(sa_tmp[i], L_mpy_ls(tmp_word32, ro_coef)); + } + + k_acc += k_coef; + } + + imbe_param->div_one_by_num_harm_sh = tmp = norm_s(num_harms); + imbe_param->div_one_by_num_harm = tmp1 = div_s(0x4000, num_harms << tmp); // calculate 1/num_harms with scaling for better pricision + // save result to use late + + sum = L_shr(L_mpy_ls(L_mpy_ls(sum, ro_coef), tmp1), (14 - tmp)); + + for (i = 1; i <= num_harms; i++) { + sa_prev1[i] = L_sub(sa_tmp[i - 1], sum); + sa[i - 1] = Pow2(sa_prev1[i]); + } + + num_harms_prev1 = num_harms; +} diff --git a/vocoder/imbe/sa_encode.cpp b/vocoder/imbe/sa_encode.cpp new file mode 100644 index 0000000..b69af18 --- /dev/null +++ b/vocoder/imbe/sa_encode.cpp @@ -0,0 +1,257 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/globals.h" +#include "imbe/basic_op.h" +#include "imbe/imbe.h" +#include "imbe/tbls.h" +#include "imbe/qnt_sub.h" +#include "imbe/aux_sub.h" +#include "imbe/math_sub.h" + +#include +#include +#include "imbe/imbe_vocoder.h" + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- + +void imbe_vocoder::sa_encode_init(void) +{ + Word16 i; + num_harms_prev2 = 30; + for (i = 0; i < NUM_HARMS_MAX + 2; i++) + sa_prev2[i] = 0; +} + +void imbe_vocoder::sa_encode(IMBE_PARAM* imbe_param) +{ + Word16 gain_vec[6], gain_r[6]; + UWord16 index, i, j, num_harms; + Word16* ba_ptr, *t_vec_ptr, *b_vec_ptr, *gss_ptr, *sa_ptr; + Word16 t_vec[NUM_HARMS_MAX], c_vec[MAX_BLOCK_LEN]; + Word32 lmprbl_item; + Word16 bl_len, step_size, num_bits, tmp, ro_coef, si_coef, tmp1; + UWord32 k_coef, k_acc; + Word32 sum, tmp_word32, vec32_tmp[NUM_HARMS_MAX], * vec32_ptr; + + num_harms = imbe_param->num_harms; + + // Calculate num_harms_prev2/num_harms. Result save in unsigned format Q8.24 + if (num_harms == num_harms_prev2) + k_coef = (Word32)CNST_ONE_Q8_24; + else if (num_harms > num_harms_prev2) + k_coef = (Word32)div_s(num_harms_prev2 << 9, num_harms << 9) << 9; + else { + // imbe_param->num_harms < num_harms_prev2 + k_coef = 0; + tmp = num_harms_prev2; + while (tmp > num_harms) { + tmp -= num_harms; + k_coef += (Word32)CNST_ONE_Q8_24; + } + k_coef += (Word32)div_s(tmp << 9, num_harms << 9) << 9; + } + + // Calculate prediction coefficient + if (num_harms <= 15) + ro_coef = CNST_0_4_Q1_15; + else if (num_harms <= 24) + ro_coef = num_harms * CNST_0_03_Q1_15 - CNST_0_05_Q1_15; + else + ro_coef = CNST_0_7_Q1_15; + + for (i = num_harms_prev2 + 1; i < NUM_HARMS_MAX + 2; i++) + sa_prev2[i] = sa_prev2[num_harms_prev2]; + + k_acc = k_coef; + sum = 0; + sa_ptr = imbe_param->sa; + vec32_ptr = vec32_tmp; + for (i = 0; i < num_harms; i++) { + index = (UWord16)(k_acc >> 24); // Get integer part + si_coef = (Word16)((k_acc - ((UWord32)index << 24)) >> 9); // Get fractional part + + + if (si_coef == 0) { + tmp_word32 = L_mpy_ls(sa_prev2[index], ro_coef); // sa_prev2 here is in Q10.22 format + *vec32_ptr = L_sub(Log2(*sa_ptr++), tmp_word32); + sum = L_add(sum, sa_prev2[index]); // sum in Q10.22 format + } + else { + tmp_word32 = L_mpy_ls(sa_prev2[index], sub(0x7FFF, si_coef)); + sum = L_add(sum, tmp_word32); + *vec32_ptr = L_sub(Log2(*sa_ptr++), L_mpy_ls(tmp_word32, ro_coef)); + + tmp_word32 = L_mpy_ls(sa_prev2[index + 1], si_coef); + sum = L_add(sum, tmp_word32); + *vec32_ptr = L_sub(*vec32_ptr, L_mpy_ls(tmp_word32, ro_coef)); + + } + if (d_gain_adjust) + *vec32_ptr = L_sub(*vec32_ptr, (Word32)(d_gain_adjust * float(1 << 22))); + vec32_ptr++; + + k_acc += k_coef; + } + + imbe_param->div_one_by_num_harm_sh = tmp = norm_s(num_harms); + imbe_param->div_one_by_num_harm = tmp1 = div_s(0x4000, num_harms << tmp); // calculate 1/num_harms with scaling for better pricision + // save result to use late + sum = L_shr(L_mpy_ls(L_mpy_ls(sum, ro_coef), tmp1), (14 - tmp)); + + for (i = 0; i < num_harms; i++) + t_vec[i] = extract_h(L_shl(L_add(vec32_tmp[i], sum), 5)); // t_vec has Q5.11 format + ////////////////////////////////////////////// + // + // Encode T vector + // + ////////////////////////////////////////////// + index = num_harms - NUM_HARMS_MIN; + + // Unpack bit allocation table's item + get_bit_allocation(num_harms, imbe_param->bit_alloc); + lmprbl_item = lmprbl_tbl[index]; + + // Encoding the Higher Order DCT Coefficients + t_vec_ptr = t_vec; + b_vec_ptr = &imbe_param->b_vec[8]; + ba_ptr = &imbe_param->bit_alloc[5]; + for (i = 0; i < NUM_PRED_RES_BLKS; i++) { + bl_len = (lmprbl_item >> 28) & 0xF; lmprbl_item <<= 4; + + dct(t_vec_ptr, bl_len, bl_len, c_vec); + gain_vec[i] = c_vec[0]; + /* + for(j = 0; j < bl_len; j++) + printf("%g ", (double)t_vec_ptr[j]/2048.); + printf("\n"); + for(j = 0; j < bl_len; j++) + printf("%g ", (double)c_vec[j]/2048.); + printf("\n"); + printf("\n"); + */ + for (j = 1; j < bl_len; j++) { + num_bits = *ba_ptr++; + if (num_bits) { + step_size = extract_h(((Word32)hi_ord_std_tbl[j - 1] * hi_ord_step_size_tbl[num_bits - 1]) << 1); + *b_vec_ptr = qnt_by_step(c_vec[j], step_size, num_bits); + } + else + *b_vec_ptr = 0; + + b_vec_ptr++; + } + t_vec_ptr += bl_len; + } + + // Encoding the Gain Vector + dct(gain_vec, NUM_PRED_RES_BLKS, NUM_PRED_RES_BLKS, gain_r); + + b_vec_ptr = &imbe_param->b_vec[2]; + ba_ptr = &imbe_param->bit_alloc[0]; + gss_ptr = (Word16*)&gain_step_size_tbl[index * 5]; + + *b_vec_ptr++ = tbl_quant(gain_r[0], (Word16*)&gain_qnt_tbl[0], GAIN_QNT_TBL_SIZE); + for (j = 1; j < 6; j++) + *b_vec_ptr++ = qnt_by_step(gain_r[j], *gss_ptr++, *ba_ptr++); + + ////////////////////////////////////////////// + // + // Decode T vector + // + ////////////////////////////////////////////// + ba_ptr = imbe_param->bit_alloc; + b_vec_ptr = &imbe_param->b_vec[2]; + + // Decoding the Gain Vector. gain_vec has signed Q5.11 format + gss_ptr = (Word16*)&gain_step_size_tbl[index * 5]; + gain_vec[0] = gain_qnt_tbl[*b_vec_ptr++]; + + for (i = 1; i < 6; i++) + gain_vec[i] = extract_l(L_shr(deqnt_by_step(*b_vec_ptr++, *gss_ptr++, *ba_ptr++), 5)); + + idct(gain_vec, NUM_PRED_RES_BLKS, NUM_PRED_RES_BLKS, gain_r); + + v_zap(t_vec, NUM_HARMS_MAX); + lmprbl_item = lmprbl_tbl[index]; + + // Decoding the Higher Order DCT Coefficients + t_vec_ptr = t_vec; + for (i = 0; i < NUM_PRED_RES_BLKS; i++) { + bl_len = (lmprbl_item >> 28) & 0xF; lmprbl_item <<= 4; + v_zap(c_vec, MAX_BLOCK_LEN); + c_vec[0] = gain_r[i]; + for (j = 1; j < bl_len; j++) { + num_bits = *ba_ptr++; + if (num_bits) { + step_size = extract_h(((Word32)hi_ord_std_tbl[j - 1] * hi_ord_step_size_tbl[num_bits - 1]) << 1); + c_vec[j] = extract_l(L_shr(deqnt_by_step(*b_vec_ptr, step_size, num_bits), 5)); + } + else + c_vec[j] = 0; + + b_vec_ptr++; + } + + idct(c_vec, bl_len, bl_len, t_vec_ptr); + t_vec_ptr += bl_len; + } + + ////////////////////////////////////////////// + // + // Reconstruct Spectral Amplitudes + // + ////////////////////////////////////////////// + k_acc = k_coef; + vec32_ptr = vec32_tmp; + + for (i = num_harms_prev2 + 1; i < NUM_HARMS_MAX + 2; i++) + sa_prev2[i] = sa_prev2[num_harms_prev2]; + + for (i = 0; i < num_harms; i++) { + index = (UWord16)(k_acc >> 24); // Get integer part + si_coef = (Word16)((k_acc - ((UWord32)index << 24)) >> 9); // Get fractional part + + if (si_coef == 0) { + tmp_word32 = L_mpy_ls(sa_prev2[index], ro_coef); // sa_prev2 here is in Q10.22 format + *vec32_ptr++ = L_add(L_shr(L_deposit_h(t_vec[i]), 5), tmp_word32); // Convert t_vec to Q10.22 and add ... + } + else { + tmp_word32 = L_mpy_ls(sa_prev2[index], sub(0x7FFF, si_coef)); + *vec32_ptr = L_add(L_shr(L_deposit_h(t_vec[i]), 5), L_mpy_ls(tmp_word32, ro_coef)); + + tmp_word32 = L_mpy_ls(sa_prev2[index + 1], si_coef); + *vec32_ptr = L_add(*vec32_ptr, L_mpy_ls(tmp_word32, ro_coef)); + + vec32_ptr++; + } + + k_acc += k_coef; + } + + for (i = 1; i <= num_harms; i++) + sa_prev2[i] = L_sub(vec32_tmp[i - 1], sum); + + num_harms_prev2 = num_harms; +} diff --git a/vocoder/imbe/sa_enh.cpp b/vocoder/imbe/sa_enh.cpp new file mode 100644 index 0000000..e66c804 --- /dev/null +++ b/vocoder/imbe/sa_enh.cpp @@ -0,0 +1,188 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/basic_op.h" +#include "imbe/imbe.h" +#include "imbe/qnt_sub.h" +#include "imbe/aux_sub.h" +#include "imbe/math_sub.h" +#include "imbe/sa_enh.h" + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// PURPOSE: +// Perform Spectral Amplitude Enhancement +// +// +// INPUT: +// IMBE_PARAM *imbe_param - pointer to IMBE_PARAM structure with +// valid num_harms, sa and fund_freq items +// +// OUTPUT: +// None +// +// RETURN: +// Enhanced Spectral Amplitudes +// +//----------------------------------------------------------------------------- +void sa_enh(IMBE_PARAM* imbe_param) +{ + Word16* sa, num_harm, sa_tmp[NUM_HARMS_MAX], nm; + Word16 cos_w[NUM_HARMS_MAX], i, tmp; + Word32 L_tmp, Rm0, Rm1; + Word32 w0, cos_acc; + Word32 L_den, L_num, L_Rm0_2, L_Rm1_2, L_sum_Rm02_Rm12, L_sum_mod; + Word16 Rm0Rm1, nm1, nm2, tot_nm; + Word16 Rm0_s, Rm1_s; + + + sa = imbe_param->sa; + num_harm = imbe_param->num_harms; + + v_equ(sa_tmp, sa, num_harm); + + Rm0 = L_v_magsq(sa, num_harm); + + if (Rm0 == 0) + return; + + nm = norm_l(Rm0); + if (Rm0 == MAX_32) { + nm = 1; + v_equ_shr(sa_tmp, sa, nm, num_harm); + Rm0 = L_v_magsq(sa_tmp, num_harm); + } + else { + if (nm > 2) { + nm = -(nm >> 1); + v_equ_shr(sa_tmp, sa, nm, num_harm); + Rm0 = L_v_magsq(sa_tmp, num_harm); + } + } + + w0 = imbe_param->fund_freq; + + cos_acc = 0; Rm1 = 0; + for (i = 0; i < num_harm; i++) { + cos_acc = L_add(cos_acc, w0); + + cos_w[i] = cos_fxp(extract_h(cos_acc)); + Rm1 = L_add(Rm1, L_mpy_ls(L_mult(sa_tmp[i], sa_tmp[i]), cos_w[i])); + } + + Rm0_s = extract_h(Rm0); + Rm1_s = extract_h(Rm1); + + L_Rm0_2 = L_mult(Rm0_s, Rm0_s); + L_Rm1_2 = L_mult(Rm1_s, Rm1_s); + L_den = L_sub(L_Rm0_2, L_Rm1_2); + L_den = L_mult(extract_h(L_den), Rm0_s); + nm1 = norm_l(L_den); + L_den = L_shl(L_den, nm1); + + nm2 = norm_l(w0); + L_den = L_mpy_ls(L_den, extract_h(L_shl(w0, nm2))); // Calculate w0 * Rm0 * (Rm0^2 - Rm1^2) + nm1 += nm2; // total denominator shift + + if (L_den < 1) return; // fix bug infinite loop due to invalid input + + L_sum_Rm02_Rm12 = L_add(L_shr(L_Rm0_2, 2), L_shr(L_Rm1_2, 2)); + Rm0Rm1 = shr(mult_r(Rm0_s, Rm1_s), 1); + + for (i = 0; i < num_harm; i++) { + if ((((i + 1) << 3) > num_harm) && (sa_tmp[i] != 0x0000)) { + L_num = L_sub(L_sum_Rm02_Rm12, L_mult(Rm0Rm1, cos_w[i])); + tot_nm = norm_l(L_num); + L_num = L_shl(L_num, tot_nm); + while (L_num >= L_den) { + L_num = L_shr(L_num, 1); + tot_nm -= 1; + } + + tmp = div_s(extract_h(L_num), extract_h(L_den)); + tot_nm -= nm1; + + L_tmp = L_mult(sa_tmp[i], sa_tmp[i]); + nm2 = norm_l(L_tmp); + L_tmp = L_shl(L_tmp, nm2); + L_tmp = L_mult(extract_h(L_tmp), tmp); + tot_nm += nm2; + tot_nm -= 2; + + if (tot_nm <= 0) { + L_tmp = L_shr(L_tmp, add(8, tot_nm)); + L_tmp = sqrt_l_exp(L_tmp, &tot_nm); + L_tmp = L_shr(L_tmp, tot_nm); + L_tmp = sqrt_l_exp(L_tmp, &tot_nm); + L_tmp = L_shr(L_tmp, tot_nm); + L_tmp = L_mult(extract_h(L_tmp), CNST_0_9898_Q1_15); + tmp = extract_h(L_shl(L_tmp, 1)); + } + else { + if (tot_nm <= 8) { + L_tmp = L_shr(L_tmp, tot_nm); + L_tmp = sqrt_l_exp(L_tmp, &tot_nm); + L_tmp = L_shr(L_tmp, tot_nm); + L_tmp = sqrt_l_exp(L_tmp, &tot_nm); + L_tmp = L_shr(L_tmp, tot_nm + 1); + tmp = mult(extract_h(L_tmp), CNST_0_9898_Q1_15); + } + else { + nm1 = tot_nm & 0xFFFE; + L_tmp = L_shr(L_tmp, tot_nm - nm1); + L_tmp = sqrt_l_exp(L_tmp, &tot_nm); + L_tmp = L_shr(L_tmp, tot_nm); + tot_nm = nm1 >> 1; + + nm1 = tot_nm & 0xFFFE; + L_tmp = L_shr(L_tmp, tot_nm - nm1); + L_tmp = sqrt_l_exp(L_tmp, &tot_nm); + L_tmp = L_shr(L_tmp, tot_nm); + L_tmp = L_mult(extract_h(L_tmp), CNST_0_9898_Q1_15); + tot_nm = nm1 >> 1; + tmp = extract_h(L_shr(L_tmp, tot_nm + 1)); + } + } + + if (tmp > CNST_1_2_Q2_14) + sa[i] = extract_h(L_shl(L_mult(sa[i], CNST_1_2_Q2_14), 1)); + else if (tmp < CNST_0_5_Q2_14) + sa[i] = shr(sa[i], 1); + else + sa[i] = extract_h(L_shl(L_mult(sa[i], tmp), 1)); + } + } + + // Compute the correct scale factor + v_equ_shr(sa_tmp, sa, nm, num_harm); + L_sum_mod = L_v_magsq(sa_tmp, num_harm); + if (L_sum_mod > Rm0) { + tmp = div_s(extract_h(Rm0), extract_h(L_sum_mod)); + L_tmp = sqrt_l_exp(L_deposit_h(tmp), &tot_nm); + tmp = shr(extract_h(L_tmp), tot_nm); + for (i = 0; i < num_harm; i++) + sa[i] = mult_r(sa[i], tmp); + } +} diff --git a/vocoder/imbe/sa_enh.h b/vocoder/imbe/sa_enh.h new file mode 100644 index 0000000..76a1fde --- /dev/null +++ b/vocoder/imbe/sa_enh.h @@ -0,0 +1,54 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ +#ifndef __SA_ENH_H__ +#define __SA_ENH_H__ + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +#define CNST_0_9898_Q1_15 0x7EB3 +#define CNST_0_5_Q2_14 0x2000 +#define CNST_1_2_Q2_14 0x4CCC + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// PURPOSE: +// Perform Spectral Amplitude Enhancement +// +// +// INPUT: +// IMBE_PARAM *imbe_param - pointer to IMBE_PARAM structure with +// valid num_harms, sa and fund_freq items +// +// OUTPUT: +// None +// +// RETURN: +// Enhanced Spectral Amplitudes +// +//----------------------------------------------------------------------------- +void sa_enh(IMBE_PARAM *imbe_param); + +#endif // __SA_ENH_H__ diff --git a/vocoder/imbe/tbls.cpp b/vocoder/imbe/tbls.cpp new file mode 100644 index 0000000..14af1a8 --- /dev/null +++ b/vocoder/imbe/tbls.cpp @@ -0,0 +1,371 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/tbls.h" + +// --------------------------------------------------------------------------- +// Globals +// --------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// +// Bit allocation and ancillary tables +// +//----------------------------------------------------------------------------- +const UWord16 bit_allocation_tbl[] = +{ + 0xA999, 0x9987, + 0x9988, 0x8976, 0x5000, + 0x8887, 0x7976, 0x5400, + 0x8777, 0x7876, 0x5430, + 0x7776, 0x6776, 0x5433, + 0x7666, 0x6775, 0x4434, 0x3000, + 0x7666, 0x5675, 0x4433, 0x3300, + 0x6665, 0x5665, 0x4433, 0x3320, + 0x6655, 0x5555, 0x4443, 0x3232, + 0x6555, 0x5545, 0x5433, 0x3322, 0x2000, + 0x6554, 0x4545, 0x4433, 0x3323, 0x2100, + 0x6554, 0x4545, 0x4433, 0x2321, 0x3210, + 0x5554, 0x4445, 0x4433, 0x2232, 0x1321, + 0x5544, 0x4444, 0x4432, 0x3223, 0x2122, 0x1000, + 0x5444, 0x4434, 0x4343, 0x2322, 0x2212, 0x2100, + 0x5444, 0x4433, 0x4333, 0x3232, 0x1221, 0x2210, + 0x5444, 0x3433, 0x4333, 0x3232, 0x1221, 0x2111, + 0x5443, 0x3433, 0x4333, 0x2232, 0x1221, 0x1221, 0x1000, + 0x5443, 0x3432, 0x4323, 0x2232, 0x2122, 0x1122, 0x1100, + 0x4443, 0x3432, 0x4323, 0x2223, 0x2112, 0x2112, 0x1110, + 0x4443, 0x3332, 0x4322, 0x3222, 0x3211, 0x2111, 0x2111, + 0x4443, 0x3332, 0x2332, 0x2322, 0x1321, 0x1211, 0x1211, 0x1000, + 0x4433, 0x3332, 0x2332, 0x2322, 0x1221, 0x1211, 0x1211, 0x1100, + 0x4433, 0x3332, 0x2332, 0x2322, 0x1221, 0x1211, 0x1121, 0x1100, + 0x4333, 0x3332, 0x2332, 0x2321, 0x1221, 0x1121, 0x1112, 0x1111, + 0x4333, 0x3322, 0x2322, 0x2322, 0x1122, 0x1112, 0x1111, 0x2111, 0x0000, + 0x4333, 0x3322, 0x2322, 0x2232, 0x1112, 0x2111, 0x2111, 0x0211, 0x1000, + 0x4333, 0x3322, 0x2132, 0x2213, 0x2111, 0x2211, 0x1211, 0x1021, 0x1100, + 0x4333, 0x2322, 0x2132, 0x2223, 0x2111, 0x2111, 0x1211, 0x1021, 0x1110, + 0x4333, 0x2322, 0x2132, 0x2213, 0x2111, 0x2111, 0x1211, 0x1102, 0x1111, 0x0000, + 0x4333, 0x2322, 0x2132, 0x2213, 0x2111, 0x2211, 0x1021, 0x1110, 0x2111, 0x0000, + 0x4333, 0x2322, 0x2132, 0x2113, 0x2111, 0x1221, 0x1102, 0x1111, 0x0211, 0x1000, + 0x4332, 0x2322, 0x1132, 0x2211, 0x3211, 0x1122, 0x1110, 0x2111, 0x1021, 0x1100, + 0x4332, 0x2322, 0x2113, 0x2221, 0x1221, 0x1112, 0x2111, 0x0211, 0x1002, 0x1110, 0x0000, + 0x4332, 0x2322, 0x2113, 0x2221, 0x1221, 0x1112, 0x1111, 0x0211, 0x1002, 0x1111, 0x0000, + 0x4332, 0x2322, 0x1113, 0x2221, 0x1221, 0x1112, 0x1111, 0x0211, 0x1100, 0x2111, 0x1000, + 0x4332, 0x2322, 0x1113, 0x2211, 0x1221, 0x1112, 0x2111, 0x0021, 0x1110, 0x0211, 0x1100, + 0x3332, 0x2322, 0x1113, 0x2211, 0x1221, 0x1111, 0x2211, 0x1002, 0x1111, 0x0021, 0x1110, 0x0000, + 0x3332, 0x2322, 0x1113, 0x2211, 0x1122, 0x1111, 0x1221, 0x1100, 0x2111, 0x1002, 0x1110, 0x0000, + 0x3332, 0x2322, 0x1111, 0x3221, 0x1112, 0x2111, 0x1122, 0x1110, 0x0211, 0x1000, 0x2111, 0x0000, + 0x3332, 0x2322, 0x1111, 0x3221, 0x1112, 0x2111, 0x1022, 0x1110, 0x0211, 0x1000, 0x2111, 0x1000, + 0x3332, 0x2322, 0x1111, 0x3221, 0x1112, 0x2111, 0x1022, 0x1110, 0x0211, 0x1100, 0x0211, 0x1000, 0x0000, + 0x3332, 0x2322, 0x1111, 0x3211, 0x1112, 0x2111, 0x1022, 0x1110, 0x0021, 0x1110, 0x0021, 0x1110, 0x0000, + 0x3322, 0x2321, 0x1111, 0x3221, 0x1112, 0x2111, 0x1102, 0x2111, 0x0002, 0x1111, 0x0002, 0x1111, 0x0000, + 0x3322, 0x2321, 0x1111, 0x3221, 0x1111, 0x2211, 0x1110, 0x2211, 0x1000, 0x2111, 0x1000, 0x2111, 0x0000, + 0x3322, 0x2322, 0x1111, 0x0322, 0x1111, 0x0221, 0x1111, 0x0221, 0x1100, 0x0211, 0x1100, 0x0211, 0x1000, 0x0000, + 0x3322, 0x2322, 0x1111, 0x0322, 0x1111, 0x0221, 0x1111, 0x0221, 0x1100, 0x0211, 0x1000, 0x0211, 0x1100, 0x0000, + 0x3322, 0x2322, 0x1111, 0x0322, 0x1111, 0x0221, 0x1111, 0x0221, 0x1100, 0x0211, 0x1100, 0x0021, 0x1100, 0x0000 +}; + +const Word16 bit_allocation_offset_tbl[] = +{ + 0x0002, 0x000E, 0x001E, 0x0032, 0x004A, 0x0066, 0x0086, 0x00AA, 0x00D2, 0x00FE, 0x012E, 0x0162 +}; + +//----------------------------------------------------------------------------- +// +// Log Magnitude Prediction Residual Block Length +// +//----------------------------------------------------------------------------- +const UWord32 lmprbl_tbl[] = +{ + 0x11122200, + 0x11222200, + 0x12222200, + 0x22222200, + 0x22222300, + 0x22223300, + 0x22233300, + 0x22333300, + 0x23333300, + 0x33333300, + 0x33333400, + 0x33334400, + 0x33344400, + 0x33444400, + 0x34444400, + 0x44444400, + 0x44444500, + 0x44445500, + 0x44455500, + 0x44555500, + 0x45555500, + 0x55555500, + 0x55555600, + 0x55556600, + 0x55566600, + 0x55666600, + 0x56666600, + 0x66666600, + 0x66666700, + 0x66667700, + 0x66677700, + 0x66777700, + 0x67777700, + 0x77777700, + 0x77777800, + 0x77778800, + 0x77788800, + 0x77888800, + 0x78888800, + 0x88888800, + 0x88888900, + 0x88889900, + 0x88899900, + 0x88999900, + 0x89999900, + 0x99999900, + 0x99999A00, + 0x9999AA00 +}; + + + +//----------------------------------------------------------------------------- +// +// Gain Quantizer Levels in signed Q5.11 format +// +//----------------------------------------------------------------------------- +const Word16 gain_qnt_tbl[] = +{ + -5821, -5518, -5239, -4880, -4549, -4292, -4057, -3760, -3370, -2903, + -2583, -2305, -1962, -1601, -1138, -711, -302, 57, 433, 795, + 1132, 1510, 1909, 2333, 2705, 3038, 3376, 3689, 3979, 4339, + 4754, 5129, 5435, 5695, 5991, 6300, 6596, 6969, 7342, 7751, + 8101, 8511, 8835, 9102, 9375, 9698, 10055, 10415, 10762, 11084, + 11403, 11752, 12123, 12468, 12863, 13239, 13615, 13997, 14382, 14770, + 15301, 15849, 16640, 17809 +}; + + +//----------------------------------------------------------------------------- +// +// Gain Ste Size in unsigned Q0.16 format +// +//----------------------------------------------------------------------------- +const UWord16 gain_step_size_tbl[] = +{ + 203, 263, 220, 190, 173, + 406, 263, 440, 380, 346, + 813, 527, 440, 760, 692, + 813, 1054, 881, 760, 692, + 1625, 1054, 881, 1425, 1298, + 1625, 1976, 1652, 1425, 1298, + 1625, 1976, 1652, 1425, 2422, + 3047, 1976, 1652, 2661, 2422, + 3047, 1976, 3083, 2661, 2422, + 3047, 3688, 3083, 2661, 2422, + 3047, 3688, 3083, 3801, 3460, + 3047, 3688, 3083, 3801, 3460, + 5689, 3688, 3083, 3801, 3460, + 5689, 3688, 4404, 3801, 3460, + 5689, 5269, 4404, 3801, 3460, + 5689, 5269, 4404, 3801, 3460, + 5689, 5269, 4404, 3801, 5623, + 5689, 5269, 4404, 6177, 5623, + 5689, 5269, 4404, 6177, 5623, + 8126, 5269, 4404, 6177, 5623, + 8126, 5269, 4404, 6177, 5623, + 8126, 5269, 4404, 6177, 5623, + 8126, 5269, 7157, 6177, 5623, + 8126, 5269, 7157, 6177, 5623, + 8126, 8562, 7157, 6177, 5623, + 8126, 8562, 7157, 6177, 5623, + 8126, 8562, 7157, 6177, 5623, + 8126, 8562, 7157, 6177, 5623, + 8126, 8562, 7157, 6177, 7353, + 8126, 8562, 7157, 6177, 7353, + 8126, 8562, 7157, 6177, 7353, + 8126, 8562, 7157, 6177, 7353, + 8126, 8562, 7157, 8077, 7353, + 8126, 8562, 7157, 8077, 7353, + 8126, 8562, 7157, 8077, 7353, + 8126, 8562, 7157, 8077, 7353, + 8126, 8562, 7157, 8077, 7353, + 13206, 8562, 7157, 8077, 7353, + 13206, 8562, 7157, 8077, 7353, + 13206, 8562, 7157, 8077, 7353, + 13206, 8562, 7157, 8077, 7353, + 13206, 8562, 7157, 8077, 7353, + 13206, 8562, 7157, 8077, 7353, + 13206, 8562, 9359, 8077, 7353, + 13206, 8562, 9359, 8077, 7353, + 13206, 8562, 9359, 8077, 7353, + 13206, 8562, 9359, 8077, 7353, + 13206, 8562, 9359, 8077, 7353 +}; + + +//----------------------------------------------------------------------------- +// +// Standard Deviation of Higher Order DCT Coefficients in unsigned Q0.16 format +// +//----------------------------------------------------------------------------- +const UWord16 hi_ord_std_tbl[] = +{ + 20120, 15794, 13566, 12452, 11731, 11338, 10813, 11141, 11141 +}; + +//----------------------------------------------------------------------------- +// +// Quantizer Step for Higher Order DCT Coefficients in unsigned Q1.15 format +// +//----------------------------------------------------------------------------- +const UWord16 hi_ord_step_size_tbl[] = +{ + 39322, 27853, 21299, 13107, 9175, 4915, 2621, 1311, 655, 328 +}; + +//----------------------------------------------------------------------------- +// +// Speech Synthesis Window +// +//----------------------------------------------------------------------------- +const Word16 ws[49] = +{ + 655, 1310, 1966, 2621, 3276, 3932, 4587, 5242, 5898, 6553, + 7208, 7864, 8519, 9175, 9830, 10485, 11141, 11796, 12451, 13107, + 13762, 14417, 15073, 15728, 16384, 17039, 17694, 18350, 19005, 19660, + 20316, 20971, 21626, 22282, 22937, 23592, 24248, 24903, 25559, 26214, + 26869, 27525, 28180, 28835, 29491, 30146, 30801, 31457, 32112 +}; + +/* +const Word16 ws_ws[49] = +{ + + 17052, 17746, 18467, 19212, 19980, 20770, 21580, 22407, 23246, 24094, + 24945, 25793, 26631, 27453, 28248, 29008, 29724, 30385, 30983, 31507, + 31950, 32302, 32559, 32715, 32767, 32715, 32559, 32302, 31950, 31507, + 30983, 30385, 29724, 29008, 28248, 27453, 26631, 25793, 24945, 24094, + 23246, 22407, 21580, 20770, 19980, 19212, 18467, 17746, 17052 +}; +*/ + +//----------------------------------------------------------------------------- +// +// Squared Pitch Estimation Window 64*wi^2 +// +//----------------------------------------------------------------------------- +const Word16 wi[301] = +{ + 15, 18, 21, 25, 29, 34, 40, 46, 52, 59, + 67, 76, 86, 96, 108, 120, 133, 148, 164, 180, + 199, 218, 239, 261, 285, 311, 338, 367, 398, 431, + 465, 502, 541, 582, 625, 671, 719, 769, 822, 878, + 936, 997, 1061, 1128, 1198, 1271, 1347, 1426, 1508, 1594, + 1683, 1775, 1871, 1970, 2073, 2179, 2289, 2403, 2520, 2641, + 2766, 2894, 3026, 3162, 3301, 3445, 3592, 3742, 3897, 4055, + 4216, 4382, 4551, 4723, 4899, 5078, 5261, 5447, 5636, 5828, + 6023, 6221, 6423, 6626, 6833, 7042, 7253, 7467, 7683, 7900, + 8120, 8341, 8564, 8788, 9014, 9241, 9468, 9696, 9925, 10154, + 10383, 10613, 10842, 11070, 11298, 11525, 11752, 11977, 12200, 12422, + 12642, 12860, 13076, 13289, 13500, 13708, 13912, 14114, 14312, 14506, + 14696, 14882, 15064, 15242, 15414, 15582, 15745, 15903, 16055, 16202, + 16343, 16478, 16608, 16731, 16848, 16958, 17062, 17159, 17250, 17333, + 17410, 17480, 17542, 17597, 17646, 17686, 17720, 17746, 17764, 17776, + 17779, 17776, 17764, 17746, 17720, 17686, 17646, 17597, 17542, 17480, + 17410, 17333, 17250, 17159, 17062, 16958, 16848, 16731, 16608, 16478, + 16343, 16202, 16055, 15903, 15745, 15582, 15414, 15242, 15064, 14882, + 14696, 14506, 14312, 14114, 13912, 13708, 13500, 13289, 13076, 12860, + 12642, 12422, 12200, 11977, 11752, 11525, 11298, 11070, 10842, 10613, + 10383, 10154, 9925, 9696, 9468, 9241, 9014, 8788, 8564, 8341, + 8120, 7900, 7683, 7467, 7253, 7042, 6833, 6626, 6423, 6221, + 6023, 5828, 5636, 5447, 5261, 5078, 4899, 4723, 4551, 4382, + 4216, 4055, 3897, 3742, 3592, 3445, 3301, 3162, 3026, 2894, + 2766, 2641, 2520, 2403, 2289, 2179, 2073, 1970, 1871, 1775, + 1683, 1594, 1508, 1426, 1347, 1271, 1198, 1128, 1061, 997, + 936, 878, 822, 769, 719, 671, 625, 582, 541, 502, + 465, 431, 398, 367, 338, 311, 285, 261, 239, 218, + 199, 180, 164, 148, 133, 120, 108, 96, 86, 76, + 67, 59, 52, 46, 40, 34, 29, 25, 21, 18, + 15 +}; + +//----------------------------------------------------------------------------- +// +// Pitch Refinement Window +// +//----------------------------------------------------------------------------- +const Word16 wr[] = +{ + 487, 570, 658, 753, 854, 962, 1076, 1197, 1325, 1460, + 1602, 1752, 1909, 2074, 2246, 2426, 2614, 2810, 3014, 3227, + 3447, 3675, 3912, 4157, 4410, 4671, 4941, 5219, 5505, 5799, + 6101, 6411, 6729, 7054, 7388, 7728, 8077, 8432, 8795, 9164, + 9541, 9923, 10312, 10707, 11108, 11515, 11927, 12344, 12766, 13192, + 13622, 14056, 14494, 14935, 15379, 15825, 16273, 16724, 17175, 17628, + 18081, 18534, 18988, 19440, 19892, 20342, 20790, 21237, 21680, 22120, + 22557, 22990, 23419, 23842, 24261, 24673, 25080, 25480, 25874, 26259, + 26638, 27008, 27370, 27722, 28066, 28400, 28724, 29037, 29340, 29632, + 29912, 30181, 30438, 30683, 30915, 31135, 31341, 31535, 31715, 31881, + 32033, 32172, 32296, 32406, 32502, 32583, 32649, 32701, 32738, 32760, +}; + +//----------------------------------------------------------------------------- +// +// Real Part Spectrum of Pitch Refinement Window * 256 +// +//----------------------------------------------------------------------------- +const Word16 wr_sp[] = +{ + 16, 43, 71, 102, 135, 170, 207, 247, 289, 333, + 380, 430, 483, 538, 596, 657, 721, 787, 857, 930, + 1006, 1085, 1168, 1254, 1343, 1435, 1531, 1630, 1733, 1840, + 1950, 2063, 2181, 2302, 2426, 2555, 2687, 2823, 2962, 3106, + 3253, 3404, 3559, 3718, 3881, 4047, 4218, 4392, 4570, 4751, + 4937, 5126, 5319, 5516, 5716, 5920, 6128, 6339, 6554, 6772, + 6994, 7219, 7447, 7679, 7914, 8152, 8393, 8637, 8884, 9134, + 9387, 9642, 9900, 10160, 10423, 10688, 10956, 11225, 11497, 11770, + 12045, 12322, 12601, 12881, 13162, 13444, 13728, 14012, 14298, 14584, + 14871, 15158, 15445, 15733, 16020, 16308, 16595, 16882, 17168, 17454, + 17738, 18022, 18305, 18586, 18866, 19145, 19421, 19696, 19969, 20240, + 20508, 20774, 21037, 21298, 21556, 21811, 22062, 22310, 22555, 22796, + 23033, 23267, 23496, 23722, 23943, 24159, 24372, 24579, 24782, 24980, + 25172, 25360, 25542, 25719, 25891, 26057, 26217, 26372, 26520, 26663, + 26800, 26930, 27055, 27173, 27285, 27390, 27489, 27581, 27667, 27746, + 27818, 27884, 27942, 27994, 28039, 28078, 28109, 28133, 28151, 28161, + 28165, 28161, 28151, 28133, 28109, 28078, 28039, 27994, 27942, 27884, + 27818, 27746, 27667, 27581, 27489, 27390, 27285, 27173, 27055, 26930, + 26800, 26663, 26520, 26372, 26217, 26057, 25891, 25719, 25542, 25360, + 25172, 24980, 24782, 24579, 24372, 24159, 23943, 23722, 23496, 23267, + 23033, 22796, 22555, 22310, 22062, 21811, 21556, 21298, 21037, 20774, + 20508, 20240, 19969, 19696, 19421, 19145, 18866, 18586, 18305, 18022, + 17738, 17454, 17168, 16882, 16595, 16308, 16020, 15733, 15445, 15158, + 14871, 14584, 14298, 14012, 13728, 13444, 13162, 12881, 12601, 12322, + 12045, 11770, 11497, 11225, 10956, 10688, 10423, 10160, 9900, 9642, + 9387, 9134, 8884, 8637, 8393, 8152, 7914, 7679, 7447, 7219, + 6994, 6772, 6554, 6339, 6128, 5920, 5716, 5516, 5319, 5126, + 4937, 4751, 4570, 4392, 4218, 4047, 3881, 3718, 3559, 3404, + 3253, 3106, 2962, 2823, 2687, 2555, 2426, 2302, 2181, 2063, + 1950, 1840, 1733, 1630, 1531, 1435, 1343, 1254, 1168, 1085, + 1006, 930, 857, 787, 721, 657, 596, 538, 483, 430, + 380, 333, 289, 247, 207, 170, 135, 102, 71, 43, + 16 +}; diff --git a/vocoder/imbe/tbls.h b/vocoder/imbe/tbls.h new file mode 100644 index 0000000..bb2e453 --- /dev/null +++ b/vocoder/imbe/tbls.h @@ -0,0 +1,100 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ +#ifndef __TBLS_H__ +#define __TBLS_H__ + +// --------------------------------------------------------------------------- +// Globals +// --------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// +// Bit allocation and ancillary tables +// +//----------------------------------------------------------------------------- +extern const UWord16 bit_allocation_tbl[]; +extern const Word16 bit_allocation_offset_tbl[]; + +//----------------------------------------------------------------------------- +// +// Log Magnitude Prediction Residual Block Length +// +//----------------------------------------------------------------------------- +extern const UWord32 lmprbl_tbl[]; + +//----------------------------------------------------------------------------- +// +// Gain Quantizer Levels in Q5.11 format +// +//----------------------------------------------------------------------------- +extern const Word16 gain_qnt_tbl[]; +#define GAIN_QNT_TBL_SIZE 64 + +//----------------------------------------------------------------------------- +// +// Gain Ste Size in unsigned Q0.16 format +// +//----------------------------------------------------------------------------- +extern const UWord16 gain_step_size_tbl[]; + +//----------------------------------------------------------------------------- +// +// Standard Deviation of Higher Order DCT Coefficients in unsigned Q0.16 format +// +//----------------------------------------------------------------------------- +extern const UWord16 hi_ord_std_tbl[]; + +//----------------------------------------------------------------------------- +// +// Quantizer Step for Higher Order DCT Coefficients in unsigned Q1.15 format +// +//----------------------------------------------------------------------------- +extern const UWord16 hi_ord_step_size_tbl[]; + +//----------------------------------------------------------------------------- +// +// Speech Synthesis Window +// +//----------------------------------------------------------------------------- +extern const Word16 ws[]; + +//----------------------------------------------------------------------------- +// +// Squared Pitch Estimation Window 64*wi^2 +// +//----------------------------------------------------------------------------- +extern const Word16 wi[]; + +//----------------------------------------------------------------------------- +// +// Pitch Refinement Window +// +//----------------------------------------------------------------------------- +extern const Word16 wr[]; + +//----------------------------------------------------------------------------- +// +// Real Part Spectrum of Pitch Refinement Window * 256 +// +//----------------------------------------------------------------------------- +extern const Word16 wr_sp[]; + +#endif // __TBLS_H__ diff --git a/vocoder/imbe/typedef.h b/vocoder/imbe/typedef.h new file mode 100644 index 0000000..566a080 --- /dev/null +++ b/vocoder/imbe/typedef.h @@ -0,0 +1,71 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ +/* +******************************************************************************** +* +* GSM AMR speech codec Version 7.4.0 January 31, 2000 +* +******************************************************************************** +* +* File : typedef.c +* Purpose : Basic types. +* +******************************************************************************** +*/ +#ifndef __TYPEDEF_H__ +#define __TYPEDEF_H__ + +#undef ORIGINAL_TYPEDEF_H /* define to get "original" ETSI version + of typedef.h */ +#ifdef ORIGINAL_TYPEDEF_H +/* +* this is the original code from the ETSI file typedef.h +*/ +#if defined(__BORLANDC__) || defined(__WATCOMC__) || defined(_MSC_VER) || defined(__ZTC__) +typedef signed char Word8; +typedef short Word16; +typedef long Word32; +typedef int Flag; + +#elif defined(__sun) +typedef signed char Word8; +typedef short Word16; +typedef long Word32; +typedef int Flag; + +#elif defined(__unix__) || defined(__unix) +typedef signed char Word8; +typedef short Word16; +typedef int Word32; +typedef int Flag; + +#endif +#else /* not original typedef.h */ + +/* +* use (improved) type definition file typdefs.h and add a "Flag" type +*/ +#include "typedefs.h" +typedef int Flag; + +#endif + +#endif // __TYPEDEF_H__ diff --git a/vocoder/imbe/typedefs.h b/vocoder/imbe/typedefs.h new file mode 100644 index 0000000..b71ad72 --- /dev/null +++ b/vocoder/imbe/typedefs.h @@ -0,0 +1,198 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + /* + ******************************************************************************** + * + * GSM AMR speech codec Version 7.4.0 January 31, 2000 + * + ******************************************************************************** + * + * File : typedefs.h + * Description : Definition of platform independent data + * types and constants + * + * + * The following platform independent data types and corresponding + * preprocessor (#define) constants are defined: + * + * defined type meaning corresponding constants + * ---------------------------------------------------------- + * Char character (none) + * Bool boolean true, false + * Word8 8-bit signed minWord8, maxWord8 + * UWord8 8-bit unsigned minUWord8, maxUWord8 + * Word16 16-bit signed minWord16, maxWord16 + * UWord16 16-bit unsigned minUWord16, maxUWord16 + * Word32 32-bit signed minWord32, maxWord32 + * UWord32 32-bit unsigned minUWord32, maxUWord32 + * Float floating point minFloat, maxFloat + * + * + * The following compile switches are #defined: + * + * PLATFORM string indicating platform progam is compiled on + * possible values: "OSF", "PC", "SUN" + * + * OSF only defined if the current platform is an Alpha + * PC only defined if the current platform is a PC + * SUN only defined if the current platform is a Sun + * + * LSBFIRST is defined if the byte order on this platform is + * "least significant byte first" -> defined on DEC Alpha + * and PC, undefined on Sun + * + ******************************************************************************** + */ +#ifndef __TYPEDEFS_H__ +#define __TYPEDEFS_H__ + +/* +******************************************************************************** +* INCLUDE FILES +******************************************************************************** +*/ +#include +#include + +#define __MSDOS__ + +/* +******************************************************************************** +* DEFINITION OF CONSTANTS +******************************************************************************** +*/ +/* + ********* define char type + */ +typedef char Char; + +/* + ********* define 8 bit signed/unsigned types & constants + */ +#if SCHAR_MAX == 127 +typedef signed char Word8; +#define minWord8 SCHAR_MIN +#define maxWord8 SCHAR_MAX + +typedef unsigned char UWord8; +#define minUWord8 0 +#define maxUWord8 UCHAR_MAX +#else +#error cannot find 8-bit type +#endif + +/* + ********* define 16 bit signed/unsigned types & constants + */ +#if INT_MAX == 32767 +typedef int Word16; +#define minWord16 INT_MIN +#define maxWord16 INT_MAX +typedef unsigned int UWord16; +#define minUWord16 0 +#define maxUWord16 UINT_MAX +#elif SHRT_MAX == 32767 +typedef short Word16; +#define minWord16 SHRT_MIN +#define maxWord16 SHRT_MAX +typedef unsigned short UWord16; +#define minUWord16 0 +#define maxUWord16 USHRT_MAX +#else +#error cannot find 16-bit type +#endif + +/* + ********* define 32 bit signed/unsigned types & constants + */ +#if INT_MAX == 2147483647 +typedef int Word32; +#define minWord32 INT_MIN +#define maxWord32 INT_MAX +typedef unsigned int UWord32; +#define minUWord32 0 +#define maxUWord32 UINT_MAX +#elif LONG_MAX == 2147483647 +typedef long Word32; +#define minWord32 LONG_MIN +#define maxWord32 LONG_MAX +typedef unsigned long UWord32; +#define minUWord32 0 +#define maxUWord32 ULONG_MAX +#else +#error cannot find 32-bit type +#endif + +/* + ********* define floating point type & constants + */ +/* use "#if 0" below if Float should be double; + use "#if 1" below if Float should be float + */ +#if 0 +typedef float Float; +#define maxFloat FLT_MAX +#define minFloat FLT_MIN +#else +typedef double Float; +#define maxFloat DBL_MAX +#define minFloat DBL_MIN +#endif + +/* + ********* define complex type + */ +typedef struct { + Float r; /* real part */ + Float i; /* imaginary part */ +} CPX; + +/* + ********* define boolean type + */ +typedef int Bool; +#define false 0 +#define true 1 + +/* + ********* Check current platform + */ +#if defined(__MSDOS__) +#define PC +#define PLATFORM "PC" +#define LSBFIRST +#elif defined(__osf__) +#define OSF +#define PLATFORM "OSF" +#define LSBFIRST +#elif defined(__sun__) || defined(__sun) +#define SUN +#define PLATFORM "SUN" +#undef LSBFIRST +#elif defined(linux) && defined(i386) +#define PC +#define PLATFORM "PC" +#define LSBFIRST +#else +#error "can't determine architecture; adapt typedefs.h to your platform" +#endif + +#endif // __TYPEDEFS_H__ diff --git a/vocoder/imbe/uv_synt.cpp b/vocoder/imbe/uv_synt.cpp new file mode 100644 index 0000000..6b6b19c --- /dev/null +++ b/vocoder/imbe/uv_synt.cpp @@ -0,0 +1,133 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/basic_op.h" +#include "imbe/imbe.h" +#include "imbe/aux_sub.h" +#include "imbe/math_sub.h" +#include "imbe/rand_gen.h" +#include "imbe/tbls.h" +#include "imbe/imbe_vocoder.h" + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- + +void imbe_vocoder::uv_synt_init(void) +{ + fft_init(); + v_zap(uv_mem, 105); +} + +void imbe_vocoder::uv_synt(IMBE_PARAM* imbe_param, Word16* snd) +{ + Cmplx16 Uw[FFTLENGTH]; + Word16 i, index_a, index_b, index_aux, ha, hb, *v_uv_dsn_ptr, *sa_ptr, sa; + Word32 fund_freq, fund_freq_2, fund_freq_acc_a, fund_freq_acc_b; + + sa_ptr = imbe_param->sa; + v_uv_dsn_ptr = imbe_param->v_uv_dsn; + fund_freq = imbe_param->fund_freq; + fund_freq_2 = L_shr(fund_freq, 1); + + v_zap((Word16*)&Uw, 2 * FFTLENGTH); + + fund_freq_acc_a = L_sub(fund_freq, fund_freq_2); + fund_freq_acc_b = L_add(fund_freq, fund_freq_2); + + for (i = 0; i < imbe_param->num_harms; i++) { + ha = extract_h(fund_freq_acc_a); + hb = extract_h(fund_freq_acc_b); + index_a = (ha >> 8) + ((ha & 0xFF) ? 1 : 0); + index_b = (hb >> 8) + ((hb & 0xFF) ? 1 : 0); + + index_aux = 256 - index_a; + + sa = shl(*sa_ptr, 3); + + if (*v_uv_dsn_ptr++) { + while (index_a < index_b) { + Uw[index_a].re = Uw[index_a].im = 0; + Uw[index_aux].re = Uw[index_aux].im = 0; + index_a++; + index_aux--; + } + } + else { + while (index_a < index_b) { + Uw[index_a].re = mult(sa, rand_gen()); + Uw[index_a].im = mult(sa, rand_gen()); + //Uw[index_a].re = sa; + //Uw[index_a].im = sa; + + Uw[index_aux].re = Uw[index_a].re; + Uw[index_aux].im = negate(Uw[index_a].im); + index_a++; + index_aux--; + } + } + + fund_freq_acc_a = L_add(fund_freq_acc_a, fund_freq); + fund_freq_acc_b = L_add(fund_freq_acc_b, fund_freq); + sa_ptr++; + } + + /* + j = 128; + for(i = 0; i < 128; i++) + Uw_tmp[j++] = Uw[i]; + + j = 128; + for(i = 0; i < 128; i++) + Uw_tmp[i] = Uw[j++]; + + for(i = 0; i < 256; i++) + Uw[i] = Uw_tmp[i]; + */ + + + fft((Word16*)&Uw, FFTLENGTH, -1); + + for (i = 0; i < 105; i++) + snd[i] = uv_mem[i]; + + index_aux = 73; + for (i = 105; i < FRAME; i++) + snd[i] = shl(Uw[index_aux++].re, 3); + + + // Weighted Overlap Add Algorithm + index_aux = 24; + index_a = 0; + index_b = 48; + for (i = 56; i < 105; i++) { + snd[i] = extract_h(L_add(L_mult(snd[i], ws[index_b]), L_mult(shl(Uw[index_aux].re, 3), ws[index_a]))); + + index_aux++; + index_a++; + index_b--; + } + + index_aux = 128; + for (i = 0; i < 105; i++) + uv_mem[i] = shl(Uw[index_aux++].re, 3); +} diff --git a/vocoder/imbe/v_synt.cpp b/vocoder/imbe/v_synt.cpp new file mode 100644 index 0000000..164bc29 --- /dev/null +++ b/vocoder/imbe/v_synt.cpp @@ -0,0 +1,229 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/basic_op.h" +#include "imbe/imbe.h" +#include "imbe/aux_sub.h" +#include "imbe/math_sub.h" +#include "imbe/rand_gen.h" +#include "imbe/tbls.h" +#include "imbe/imbe_vocoder.h" + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +#define CNST_0_1_Q1_15 0x0CCD + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- + +void imbe_vocoder::v_synt_init(void) +{ + Word16 i; + + for (i = 0; i < NUM_HARMS_MAX; i++) { + ph_mem[i] = L_deposit_h(rand_gen()); + vu_dsn_prev[i] = 0; + } + + num_harms_prev3 = 0; + fund_freq_prev = 0; +} + +void imbe_vocoder::v_synt(IMBE_PARAM* imbe_param, Word16* snd) +{ + Word32 L_tmp, L_tmp1, fund_freq, L_snd[FRAME], L_ph_acc, L_ph_step; + Word32 L_ph_acc_aux, L_ph_step_prev, L_amp_acc, L_amp_step, L_ph_step_aux; + Word16 num_harms, i, j, *vu_dsn, *sa, *s_ptr, *s_ptr_aux, num_harms_max, num_harms_max_4; + UWord32 ph_mem_prev[NUM_HARMS_MAX], dph[NUM_HARMS_MAX]; + Word16 num_harms_inv, num_harms_sh, num_uv; + Word16 freq_flag; + + + fund_freq = imbe_param->fund_freq; + num_harms = imbe_param->num_harms; + vu_dsn = imbe_param->v_uv_dsn; + sa = imbe_param->sa; + num_harms_inv = imbe_param->div_one_by_num_harm; + num_harms_sh = imbe_param->div_one_by_num_harm_sh; + num_uv = imbe_param->l_uv; + + for (i = 0; i < FRAME; i++) + L_snd[i] = 0; + + // Update phases (calculated phase value correspond to bound of frame) + L_tmp = (((fund_freq_prev + fund_freq) >> 7) * FRAME / 2) << 7; // It is performed integer multiplication by mod 1 + + L_ph_acc = 0; + for (i = 0; i < NUM_HARMS_MAX; i++) { + ph_mem_prev[i] = ph_mem[i]; + L_ph_acc += L_tmp; + ph_mem[i] += L_ph_acc; + dph[i] = 0; + } + + num_harms_max = (num_harms >= num_harms_prev3) ? num_harms : num_harms_prev3; + num_harms_max_4 = num_harms_max >> 2; + + if (L_abs(L_sub(fund_freq, fund_freq_prev)) >= L_mpy_ls(fund_freq, CNST_0_1_Q1_15)) + freq_flag = 1; + else + freq_flag = 0; + + L_ph_step = L_ph_step_prev = 0; + for (i = 0; i < num_harms_max; i++) { + L_ph_step += fund_freq; + L_ph_step_prev += fund_freq_prev; + + + if (i > num_harms_max_4) { + if (num_uv == num_harms) { + dph[i] = L_deposit_h(rand_gen()); + } + else { + L_tmp = L_mult(rand_gen(), num_harms_inv); + dph[i] = L_shr(L_tmp, 15 - num_harms_sh) * num_uv; + } + ph_mem[i] += dph[i]; + } + + if (vu_dsn[i] == 0 && vu_dsn_prev[i] == 0) + continue; + + if (vu_dsn[i] == 1 && vu_dsn_prev[i] == 0) // unvoiced => voiced + { + s_ptr = (Word16*)ws; + L_ph_acc = ph_mem[i] - (((L_ph_step >> 7) * 104) << 7); + for (j = 56; j <= 104; j++) { + L_tmp = L_mult(*s_ptr++, sa[i]); + L_tmp = L_mpy_ls(L_tmp, cos_fxp(extract_h(L_ph_acc))); + L_tmp = L_shr(L_tmp, 1); + L_snd[j] = L_add(L_snd[j], L_tmp); + L_ph_acc += L_ph_step; + } + + for (j = 105; j <= 159; j++) { + L_tmp = L_mult(sa[i], cos_fxp(extract_h(L_ph_acc))); + L_tmp = L_shr(L_tmp, 1); + L_snd[j] = L_add(L_snd[j], L_tmp); + L_ph_acc += L_ph_step; + } + continue; + } + + + if (vu_dsn[i] == 0 && vu_dsn_prev[i] == 1) // voiced => unvoiced + { + s_ptr = (Word16*)&ws[48]; + L_ph_acc = ph_mem_prev[i]; + + for (j = 0; j <= 55; j++) { + L_tmp = L_mult(sa_prev3[i], cos_fxp(extract_h(L_ph_acc))); + L_tmp = L_shr(L_tmp, 1); + L_snd[j] = L_add(L_snd[j], L_tmp); + L_ph_acc += L_ph_step_prev; + } + + for (j = 56; j <= 104; j++) { + L_tmp = L_mult(*s_ptr--, sa_prev3[i]); + L_tmp = L_mpy_ls(L_tmp, cos_fxp(extract_h(L_ph_acc))); + L_tmp = L_shr(L_tmp, 1); + L_snd[j] = L_add(L_snd[j], L_tmp); + L_ph_acc += L_ph_step_prev; + } + continue; + } + + if (i >= 7 || freq_flag) { + s_ptr_aux = (Word16*)&ws[48]; + L_ph_acc_aux = ph_mem_prev[i]; + + s_ptr = (Word16*)ws; + L_ph_acc = ph_mem[i] - (((L_ph_step >> 7) * 104) << 7); + + for (j = 0; j <= 55; j++) { + L_tmp = L_mult(sa_prev3[i], cos_fxp(extract_h(L_ph_acc_aux))); + L_tmp = L_shr(L_tmp, 1); + L_snd[j] = L_add(L_snd[j], L_tmp); + L_ph_acc_aux += L_ph_step_prev; + } + + for (j = 56; j <= 104; j++) { + L_tmp = L_mult(*s_ptr_aux--, sa_prev3[i]); + L_tmp = L_mpy_ls(L_tmp, cos_fxp(extract_h(L_ph_acc_aux))); + L_tmp = L_shr(L_tmp, 1); + L_snd[j] = L_add(L_snd[j], L_tmp); + + L_tmp = L_mult(*s_ptr++, sa[i]); + L_tmp = L_mpy_ls(L_tmp, cos_fxp(extract_h(L_ph_acc))); + L_tmp = L_shr(L_tmp, 1); + L_snd[j] = L_add(L_snd[j], L_tmp); + + L_ph_acc_aux += L_ph_step_prev; + L_ph_acc += L_ph_step; + } + + for (j = 105; j <= 159; j++) { + L_tmp = L_mult(sa[i], cos_fxp(extract_h(L_ph_acc))); + L_tmp = L_shr(L_tmp, 1); + L_snd[j] = L_add(L_snd[j], L_tmp); + L_ph_acc += L_ph_step; + } + continue; + } + + L_amp_step = L_mpy_ls(L_shr(L_deposit_h(sub(sa[i], sa_prev3[i])), 4 + 1), CNST_0_1_Q1_15); // (sa[i] - sa_prev3[i]) / 160, 1/160 = 0.1/16 + L_amp_acc = L_shr(L_deposit_h(sa_prev3[i]), 1); + + + L_ph_step_aux = L_mpy_ls(L_shr(fund_freq - fund_freq_prev, 4 + 1), CNST_0_1_Q1_15); // (fund_freq - fund_freq_prev)/(2*160) + L_ph_step_aux = ((L_ph_step_aux >> 7) * (i + 1)) << 7; + + L_ph_acc = ph_mem_prev[i]; + + L_tmp1 = L_mpy_ls(L_shr(dph[i], 4), CNST_0_1_Q1_15); // dph[i] / 160 + + for (j = 0; j < 160; j++) { + L_ph_acc_aux = ((L_ph_step_aux >> 9) * j) << 9; + L_ph_acc_aux = ((L_ph_acc_aux >> 9) * j) << 9; + + L_tmp = L_mpy_ls(L_amp_acc, cos_fxp(extract_h(L_ph_acc + L_ph_acc_aux))); + L_snd[j] = L_add(L_snd[j], L_tmp); + + L_amp_acc = L_add(L_amp_acc, L_amp_step); + L_ph_acc += L_ph_step_prev; + L_ph_acc += L_tmp1; + } + } + + for (i = 0; i < FRAME; i++) + *snd++ = extract_h(L_snd[i]); + + v_zap(vu_dsn_prev, NUM_HARMS_MAX); + v_equ(vu_dsn_prev, imbe_param->v_uv_dsn, num_harms); + v_equ(sa_prev3, imbe_param->sa, num_harms); + + num_harms_prev3 = num_harms; + fund_freq_prev = fund_freq; +} diff --git a/vocoder/imbe/v_uv_det.cpp b/vocoder/imbe/v_uv_det.cpp new file mode 100644 index 0000000..846cb2b --- /dev/null +++ b/vocoder/imbe/v_uv_det.cpp @@ -0,0 +1,356 @@ +/* + * Project 25 IMBE Encoder/Decoder Fixed-Point implementation + * Developed by Pavel Yazev E-mail: pyazev@gmail.com + * Version 1.0 (c) Copyright 2009 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * The software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Boston, MA + * 02110-1301, USA. + */ + +#include "imbe/typedef.h" +#include "imbe/globals.h" +#include "imbe/imbe.h" +#include "imbe/basic_op.h" +#include "imbe/aux_sub.h" +#include "imbe/math_sub.h" +#include "imbe/tbls.h" +#include "imbe/imbe_vocoder.h" + +#include +#include +#include + +#if defined(__GNUC__) || defined(__GNUG__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#endif + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +#define CNST_0_5625_Q1_15 0x4800 +#define CNST_0_45_Q1_15 0x3999 +#define CNST_0_1741_Q1_15 0x164A +#define CNST_0_1393_Q1_15 0x11D5 +#define CNST_0_99_Q1_15 0x7EB8 +#define CNST_0_01_Q1_15 0x0148 +#define CNST_0_0025_Q1_15 0x0051 +#define CNST_0_25_Q1_15 0x2000 +#define CNST_PI_4_Q1_15 0x6488 +#define CNST_0_55_Q4_12 0x08CD + +// --------------------------------------------------------------------------- +// Globals +// --------------------------------------------------------------------------- + +extern FILE* fp_in, *fp_out; +extern int frame_cnt; + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- + +void imbe_vocoder::pitch_ref_init(void) +{ + v_zap(v_uv_dsn, NUM_BANDS_MAX); + th_max = 0; +} + +Word16 imbe_vocoder::voiced_sa_calc(Word32 num, Word16 den) +{ + Word16 tmp; + Word32 L_tmp; + + L_tmp = L_mpy_ls(num, den); + L_tmp = sqrt_l_exp(L_tmp, &tmp); + L_tmp = L_shr(L_tmp, tmp - 3); + + //L_tmp =0; + //return (Word16)(2*256.0*sqrt(2*(double)num/(double)den)); + return extract_h(L_tmp); +} + +Word16 imbe_vocoder::unvoiced_sa_calc(Word32 num, Word16 den) +{ + Word16 shift, tmp; + Word32 L_tmp; + + shift = norm_s(den); + tmp = div_s(0x4000, shl(den, shift)); + L_tmp = L_shl(L_mpy_ls(num, tmp), shift + 2); + L_tmp = sqrt_l_exp(L_tmp, &tmp); + L_tmp = L_shr(L_tmp, tmp - 2 + 6); + L_tmp = L_mpy_ls(L_tmp, 0x4A76); + + //L_tmp =0; + //return (Word16)(2*0.1454 * sqrt(2*256*(double)num/(double)den)); + return extract_h(L_tmp); +} + +//============================================================================= +// +// Voiced/Unvoiced Determination & Spectral Amplitudes Estimation +// +//============================================================================= +void imbe_vocoder::v_uv_det(IMBE_PARAM* imbe_param, Cmplx16* fft_buf) +{ + Word16 i, j, index_a_save, tmp, index_wr; + Word32 fund_freq, fund_freq_2, fund_freq_acc_a, fund_freq_acc_b, fund_freq_acc, fund_fr_acc, L_tmp, amp_re_acc, amp_im_acc; + Word16 ha, hb, index_a, index_b, index_tbl[30], it_ind, re_tmp, im_tmp, re_tmp2, im_tmp2, sc_coef; + Word32 Sw_sum, M_num[NUM_HARMS_MAX], M_num_sum, M_den_sum, D_num, D_den, th_lf, th_hf, th0, fund_fr_step, M_fcn_num, M_fcn_den; + Word16 sp_rec_re, sp_rec_im, M_fcn; + Word16 band_cnt, num_harms_cnt, uv_harms_cnt, Dk; + Word16 num_harms, num_bands, dsn_thr = 0; + Word16 thr[NUM_BANDS_MAX], M_den[NUM_HARMS_MAX], b1_vec; + + + fund_freq = imbe_param->fund_freq; + + tmp = shr(add(shr(imbe_param->ref_pitch, 1), CNST_0_25_Q8_8), 8); // fix(pitch_cand / 2 + 0.5) + num_harms = extract_h((UWord32)CNST_0_9254_Q0_16 * tmp); // fix(0.9254 * fix(pitch_cand / 2 + 0.5)) + if (num_harms < NUM_HARMS_MIN) + num_harms = NUM_HARMS_MIN; + else if (num_harms > NUM_HARMS_MAX) + num_harms = NUM_HARMS_MAX; + + if (num_harms <= 36) + num_bands = extract_h((UWord32)(num_harms + 2) * CNST_0_33_Q0_16); // fix((L+2)/3) + else + num_bands = NUM_BANDS_MAX; + + imbe_param->num_harms = num_harms; + imbe_param->num_bands = num_bands; + + //========================================================================= + // + // M(th) function calculation + // + //========================================================================= + for (j = 0, th_lf = 0; j < 64; j++) { + th_lf = L_mac(th_lf, fft_buf[j].re, fft_buf[j].re); + th_lf = L_mac(th_lf, fft_buf[j].im, fft_buf[j].im); + } + for (j = 64, th_hf = 0; j < 128; j++) { + th_hf = L_mac(th_hf, fft_buf[j].re, fft_buf[j].re); + th_hf = L_mac(th_hf, fft_buf[j].im, fft_buf[j].im); + } + th0 = L_add(th_lf, th_hf); + + if (th0 > th_max) + th_max = L_shr(L_add(th_max, th0), 1); + else + th_max = L_add(L_mpy_ls(th_max, CNST_0_99_Q1_15), L_mpy_ls(th0, CNST_0_01_Q1_15)); + + M_fcn_num = L_add(th0, L_mpy_ls(th_max, CNST_0_0025_Q1_15)); + M_fcn_den = L_add(th0, L_mpy_ls(th_max, CNST_0_01_Q1_15)); + if (M_fcn_den == 0) + M_fcn = CNST_0_25_Q1_15; + else { + tmp = norm_l(M_fcn_den); + M_fcn_den = L_shl(M_fcn_den, tmp); + M_fcn_num = L_shl(M_fcn_num, tmp); + + M_fcn = div_s(extract_h(M_fcn_num), extract_h(M_fcn_den)); + + if (th_lf < (L_tmp = L_add(L_shl(th_hf, 2), th_hf))) // compare th_lf < 5*th_hf + { + tmp = norm_l(L_tmp); + M_fcn_den = L_shl(L_tmp, tmp); + th_lf = L_shl(th_lf, tmp); + + tmp = div_s(extract_h(th_lf), extract_h(M_fcn_den)); + L_tmp = sqrt_l_exp(L_deposit_h(tmp), &tmp); + if (tmp) + L_tmp = L_shr(L_tmp, tmp); + M_fcn = mult(M_fcn, extract_h(L_tmp)); + } + } + // ======================================================================== + fund_fr_step = L_shl(L_mpy_ls(fund_freq, CNST_PI_4_Q1_15), 2); // mult by PI + + uv_harms_cnt = 0; + b1_vec = 0; + band_cnt = 0; + num_harms_cnt = 0; + Sw_sum = 0; + D_num = D_den = 0; + + fund_fr_acc = 0; + fund_freq_acc = fund_freq; + fund_freq_2 = L_shr(fund_freq, 1); + fund_freq_acc_a = L_sub(fund_freq, fund_freq_2); + fund_freq_acc_b = L_add(fund_freq, fund_freq_2); + for (j = 0; j < num_harms; j++) { + ha = extract_h(fund_freq_acc_a); + hb = extract_h(fund_freq_acc_b); + index_a = (ha >> 8) + ((ha & 0xFF) ? 1 : 0); + index_b = (hb >> 8) + ((hb & 0xFF) ? 1 : 0); + + L_tmp = L_shl(L_deposit_h(index_a), 8); + L_tmp = L_sub(L_tmp, fund_freq_acc); + L_tmp = L_add(L_tmp, 0x00020000); // for rounding purpose + L_tmp = L_shr(L_tmp, 2); + + index_a_save = index_a; + it_ind = 0; + + // =========== v/uv determination threshold function == + if (num_harms_cnt == 0) // calculate one time per band + { + if (imbe_param->e_p > CNST_0_55_Q4_12 && band_cnt >= 1) + dsn_thr = 0; + else if (v_uv_dsn[band_cnt] == 1) + dsn_thr = mult(M_fcn, sub(CNST_0_5625_Q1_15, mult(CNST_0_1741_Q1_15, extract_h(fund_fr_acc)))); + else + dsn_thr = mult(M_fcn, sub(CNST_0_45_Q1_15, mult(CNST_0_1393_Q1_15, extract_h(fund_fr_acc)))); + + fund_fr_acc = L_add(fund_fr_acc, fund_fr_step); + + thr[band_cnt] = dsn_thr; + } + // ==================================================== + + M_den_sum = 0; + amp_re_acc = amp_im_acc = 0; + while (index_a < index_b) { + index_wr = extract_h(L_tmp); + if (index_wr < 0 && (L_tmp & 0xFFFF)) // truncating for negative number + index_wr = add(index_wr, 1); + index_wr = add(index_wr, 160); + index_tbl[it_ind++] = index_wr; + if (index_wr >= 0 && index_wr <= 320) { + amp_re_acc = L_mac(amp_re_acc, fft_buf[index_a].re, wr_sp[index_wr]); + amp_im_acc = L_mac(amp_im_acc, fft_buf[index_a].im, wr_sp[index_wr]); + M_den_sum = L_add(M_den_sum, mult(wr_sp[index_wr], wr_sp[index_wr])); + } + + index_a++; + L_tmp = L_add(L_tmp, 0x400000); + } + sc_coef = div_s(0x4000, extract_l(L_shr(M_den_sum, 1))); + im_tmp2 = mult(extract_h(amp_im_acc), sc_coef); + re_tmp2 = mult(extract_h(amp_re_acc), sc_coef); + + M_num_sum = 0; + it_ind = 0; + index_a = index_a_save; + while (index_a < index_b) { + index_wr = index_tbl[it_ind++]; + if (index_wr < 0 || index_wr > 320) + sp_rec_re = sp_rec_im = 0; + else { + sp_rec_im = mult(im_tmp2, wr_sp[index_wr]); + sp_rec_re = mult(re_tmp2, wr_sp[index_wr]); + } + + re_tmp = sub(fft_buf[index_a].re, sp_rec_re); + im_tmp = sub(fft_buf[index_a].im, sp_rec_im); + D_num = L_mac(D_num, re_tmp, re_tmp); + D_num = L_mac(D_num, im_tmp, im_tmp); + + M_num_sum = L_mac(M_num_sum, fft_buf[index_a].re, fft_buf[index_a].re); + M_num_sum = L_mac(M_num_sum, fft_buf[index_a].im, fft_buf[index_a].im); + + index_a++; + } + + M_den[j] = sc_coef; + M_num[j] = M_num_sum; + D_den = L_add(D_den, M_num_sum); + + if (++num_harms_cnt == 3 && band_cnt < num_bands - 1) { + b1_vec <<= 1; + + if (D_den > D_num && D_den != 0) { + tmp = norm_l(D_den); + Dk = div_s(extract_h(L_shl(D_num, tmp)), extract_h(L_shl(D_den, tmp))); + } + else + Dk = MAX_16; + + if (Dk < dsn_thr) { + // voiced band + v_uv_dsn[band_cnt] = 1; + b1_vec |= 1; + i = j - 2; + while (i <= j) { + imbe_param->sa[i] = voiced_sa_calc(M_num[i], M_den[i]); + imbe_param->v_uv_dsn[i] = 1; + i++; + } + } + else { + // unvoiced band + v_uv_dsn[band_cnt] = 0; + i = j - 2; + while (i <= j) { + imbe_param->sa[i] = unvoiced_sa_calc(M_num[i], index_b - index_a_save); + imbe_param->v_uv_dsn[i] = 0; + uv_harms_cnt++; + i++; + } + } + + D_num = D_den = 0; + num_harms_cnt = 0; + band_cnt++; + } + + + fund_freq_acc_a = L_add(fund_freq_acc_a, fund_freq); + fund_freq_acc_b = L_add(fund_freq_acc_b, fund_freq); + fund_freq_acc = L_add(fund_freq_acc, fund_freq); + } + + if (num_harms_cnt) { + b1_vec <<= 1; + if (D_den > D_num && D_den != 0) { + tmp = norm_l(D_den); + Dk = div_s(extract_h(L_shl(D_num, tmp)), extract_h(L_shl(D_den, tmp))); + } + else + Dk = MAX_16; + + if (Dk < dsn_thr) { + // voiced band + v_uv_dsn[band_cnt] = 1; + b1_vec |= 1; + + i = num_harms - num_harms_cnt; + while (i < num_harms) { + imbe_param->sa[i] = voiced_sa_calc(M_num[i], M_den[i]); + imbe_param->v_uv_dsn[i] = 1; + i++; + } + } + else { + // unvoiced band + v_uv_dsn[band_cnt] = 0; + i = num_harms - num_harms_cnt; + while (i < num_harms) { + imbe_param->sa[i] = unvoiced_sa_calc(M_num[i], index_b - index_a_save); + imbe_param->v_uv_dsn[i] = 0; + uv_harms_cnt++; + i++; + } + } + } + + imbe_param->l_uv = uv_harms_cnt; + + + imbe_param->b_vec[1] = b1_vec; // Save encoded voiced/unvoiced decision + imbe_param->b_vec[0] = shr(sub(imbe_param->ref_pitch, 0x1380), 7); // Pitch encode fix(2*pitch - 39) +} diff --git a/vocoder/imbe7200x4400.c b/vocoder/imbe7200x4400.c new file mode 100644 index 0000000..3411b69 --- /dev/null +++ b/vocoder/imbe7200x4400.c @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - MBE Vocoder + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + */ + +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#define _USE_MATH_DEFINES +#include + +#include "mbe.h" +#include "imbe7200x4400_const.h" + +#ifdef _MSC_VER +#pragma warning(disable: 4244) +#endif +#if defined(__GNUC__) || defined(__GNUG__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#endif + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +/* */ + +int mbe_eccImbe7200x4400C0(char imbe_fr[8][23]) +{ + int j, errs; + char in[23], out[23]; + + for (j = 0; j < 23; j++) { + in[j] = imbe_fr[0][j]; + } + + errs = mbe_golay2312(in, out); + for (j = 0; j < 23; j++) { + imbe_fr[0][j] = out[j]; + } + + return (errs); +} + +/* */ + +int mbe_eccImbe7200x4400Data(char imbe_fr[8][23], char* imbe_d) +{ + int i, j, errs; + char* imbe, gin[23], gout[23], hin[15], hout[15]; + + errs = 0; + imbe = imbe_d; + for (i = 0; i < 4; i++) { + if (i > 0) { + for (j = 0; j < 23; j++) { + gin[j] = imbe_fr[i][j]; + } + + errs += mbe_golay2312(gin, gout); + for (j = 22; j > 10; j--) { + *imbe = gout[j]; + imbe++; + } + } + else { + for (j = 22; j > 10; j--) { + *imbe = imbe_fr[i][j]; + imbe++; + } + } + } + + for (i = 4; i < 7; i++) { + for (j = 0; j < 15; j++) { + hin[j] = imbe_fr[i][j]; + } + + errs += mbe_hamming1511(hin, hout); + for (j = 14; j >= 4; j--) { + *imbe = hout[j]; + imbe++; + } + } + + for (j = 6; j >= 0; j--) { + *imbe = imbe_fr[7][j]; + imbe++; + } + + return (errs); +} + +/* */ + +int mbe_decodeImbe4400Parms(char* imbe_d, mbe_parms* cur_mp, mbe_parms* prev_mp) +{ + int Bm, ji, b, i, j, k, l, L, K, L9, m, am, ak; + int intkl[57]; + int b0, b2, bm; + float Cik[7][11], rho, flokl[57], deltal[57]; + float Sum77, Tl[57], Gm[7], Ri[7], sum, c1, c2; + const float* ba1, *ba2; + char tmpstr[13]; + const int* bo1, *bo2; + char bb[58][12]; + + // copy repeat from prev_mp + cur_mp->repeat = prev_mp->repeat; + + // decode fundamental frequency w0 from b0 + tmpstr[8] = 0; + tmpstr[0] = imbe_d[0] + 48; + tmpstr[1] = imbe_d[1] + 48; + tmpstr[2] = imbe_d[2] + 48; + tmpstr[3] = imbe_d[3] + 48; + tmpstr[4] = imbe_d[4] + 48; + tmpstr[5] = imbe_d[5] + 48; + tmpstr[6] = imbe_d[85] + 48; + tmpstr[7] = imbe_d[86] + 48; + b0 = strtol(tmpstr, NULL, 2); + + if (b0 > 207) { + if ((b0 >= 216) && (b0 <= 219)) { +#ifdef IMBE_DEBUG + fprintf(stderr, "MBE: IMBE: Silence"); +#endif + } + else { +#ifdef IMBE_DEBUG + fprintf(stderr, "MBE: IMBE: Invalid fundamental frequency"); +#endif + } + return (1); + } + + cur_mp->w0 = ((float)(4 * M_PI) / (float)((float)b0 + 39.5)); + + // decode L from w0 + L = (int)(0.9254 * (int)((M_PI / cur_mp->w0) + 0.25)); + if ((L > 56) || (L < 9)) { +#ifdef IMBE_DEBUG + fprintf(stderr, "MBE: IMBE: invalid L: %i", L); +#endif + return (1); + } + + cur_mp->L = L; + L9 = L - 9; + + // decode K from L + if (L < 37) { + K = (int)((float)(L + 2) / (float)3); + cur_mp->K = K; + } + else { + K = 12; + cur_mp->K = 12; + } + +#ifdef IMBE_DEBUG + fprintf(stderr, "MBE: IMBE: b0:%i L:%i K:%i", b0, L, K); +#endif + + // read bits from imbe_d into b0..bL+1 + bo1 = bo[L9][0]; + bo2 = bo1 + 1; + for (i = 6; i < 85; i++) { + bb[*bo1][*bo2] = imbe_d[i]; +#ifdef IMBE_DEBUG + fprintf(stderr, "MBE: IMBE: bo1: %i, bo2: %i", *bo1, *bo2); +#endif + bo1 += 2; + bo2 += 2; + } + + // Vl + j = 1; + k = (K - 1); + for (i = 1; i <= L; i++) { + cur_mp->Vl[i] = bb[1][k]; + if (j == 3) { + j = 1; + if (k > 0) { + k--; + } + else { + k = 0; + } + } + else { + j++; + } + } + + // decode G1 from b2 + tmpstr[6] = 0; + tmpstr[0] = bb[2][5] + 48; + tmpstr[1] = bb[2][4] + 48; + tmpstr[2] = bb[2][3] + 48; + tmpstr[3] = bb[2][2] + 48; + tmpstr[4] = bb[2][1] + 48; + tmpstr[5] = bb[2][0] + 48; + b2 = strtol(tmpstr, NULL, 2); + Gm[1] = B2[b2]; +#ifdef IMBE_DEBUG + fprintf(stderr, "MBE: IMBE: G1: %e, %s, %i", Gm[1], tmpstr, b2); +#endif + +#ifdef IMBE_DEBUG + fprintf(stderr, "MBE: IMBE: tmpstr: %s b2: %i g1: %e", tmpstr, b2, Gm[1]); +#endif + + // decode G2..G6 (from b3..b7) with annex E + // equation 68 + ba1 = ba[L9][0]; + ba2 = ba1 + 1; + + for (i = 2; i < 7; i++) { + tmpstr[(int)*ba1] = 0; + k = 0; + for (j = ((int)*ba1 - 1); j >= 0; j--) { + tmpstr[k] = bb[i + 1][j] + 48; + k++; + } + bm = strtol(tmpstr, NULL, 2); + Gm[i] = (*ba2 * ((float)bm - powf(2, (*ba1 - 1)) + (float)0.5)); +#ifdef IMBE_DEBUG + fprintf(stderr, "MBE: IMBE: G%i: %e, %s, %i, ba1: %e, ba2: %e", i, Gm[i], tmpstr, bm, *ba1, *ba2); +#endif + ba1 += 2; + ba2 += 2; + } + + // inverse DCT Gi to give Ri (also known as Ci,1) + for (i = 1; i <= 6; i++) { + sum = 0; + for (m = 1; m <= 6; m++) { + if (m == 1) { + am = 1; + } + else { + am = 2; + } + sum = sum + ((float)am * Gm[m] * cosf((M_PI * (float)(m - 1) * ((float)i - 0.5)) / (float)6)); +#ifdef IMBE_DEBUG + fprintf(stderr, "MBE: IMBE: sum: %e ", sum); +#endif + } + Ri[i] = sum; +#ifdef IMBE_DEBUG + fprintf(stderr, "MBE: IMBE: R%i: %e", i, Ri[i]); +#endif + } +#ifdef IMBE_DEBUG + fprintf(stderr, "MBE: IMBE: R1: %e", Ri[1]); +#endif + + // load b8..bL+1 into Ci,k + m = 8; + for (i = 1; i <= 6; i++) { + Cik[i][1] = Ri[i]; + for (k = 2; k <= ImbeJi[L9][i - 1]; k++) { + Bm = hoba[L9][m - 8]; + for (b = 0; b < Bm; b++) { + tmpstr[b] = bb[m][(Bm - b) - 1] + 48; + } + + if (Bm == 0) { + Cik[i][k] = 0; + } + else { + tmpstr[Bm] = 0; + bm = strtol(tmpstr, NULL, 2); + Cik[i][k] = ((quantstep[Bm - 1] * standdev[k - 2]) * (((float)bm - powf(2, (Bm - 1))) + 0.5)); + } + m++; + } + } + + // inverse DCT each Ci,k to give ci,j (Tl) + l = 1; + for (i = 1; i <= 6; i++) { + ji = ImbeJi[L9][i - 1]; + for (j = 1; j <= ji; j++) { + sum = 0; + for (k = 1; k <= ji; k++) { + if (k == 1) { + ak = 1; + } + else { + ak = 2; + } + sum = sum + ((float)ak * Cik[i][k] * cosf((M_PI * (float)(k - 1) * ((float)j - 0.5)) / (float)ji)); + } + Tl[l] = sum; + l++; + } + } +#ifdef IMBE_DEBUG + fprintf(stderr, "MBE: IMBE: T1: %e", Tl[1]); +#endif + + // determine log2Ml by applying ci,j to previous log2Ml + if (cur_mp->L <= 15) { + rho = 0.4; + } + else if (cur_mp->L <= 24) { + rho = (0.03 * (float)cur_mp->L) - 0.05; + } + else { + rho = 0.7; + } + + // fix for when L > L(-1) + if (cur_mp->L > prev_mp->L) { + for (l = prev_mp->L + 1; l <= cur_mp->L; l++) { + prev_mp->Ml[l] = prev_mp->Ml[prev_mp->L]; + prev_mp->log2Ml[l] = prev_mp->log2Ml[prev_mp->L]; + } + } + + // Part 1 + Sum77 = 0; + for (l = 1; l <= cur_mp->L; l++) { + // eq. 75 + flokl[l] = ((float)prev_mp->L / (float)cur_mp->L) * (float)l; + intkl[l] = (int)(flokl[l]); +#ifdef IMBE_DEBUG + fprintf(stderr, "MBE: IMBE: flokl: %e, intkl: %i", flokl[l], intkl[l]); +#endif + // eq. 76 + deltal[l] = flokl[l] - (float)intkl[l]; +#ifdef IMBE_DEBUG + fprintf(stderr, "MBE: IMBE: deltal: %e", deltal[l]); +#endif + // eq 77 + Sum77 = Sum77 + ((((float)1 - deltal[l]) * prev_mp->log2Ml[intkl[l]]) + (deltal[l] * prev_mp->log2Ml[intkl[l] + 1])); + } + Sum77 = ((rho / (float)cur_mp->L) * Sum77); + +#ifdef IMBE_DEBUG + fprintf(stderr, "MBE: IMBE: Sum77: %e", Sum77); +#endif + + // Part 2 + for (l = 1; l <= cur_mp->L; l++) { + c1 = (rho * ((float)1 - deltal[l]) * prev_mp->log2Ml[intkl[l]]); + c2 = (rho * deltal[l] * prev_mp->log2Ml[intkl[l] + 1]); + cur_mp->log2Ml[l] = Tl[l] + c1 + c2 - Sum77; + cur_mp->Ml[l] = powf(2, cur_mp->log2Ml[l]); +#ifdef IMBE_DEBUG + fprintf(stderr, "MBE: IMBE: rho: %e c1: %e c2: %e Sum77: %e T%i: %e log2M%i: %e M%i: %e", rho, c1, c2, Sum77, l, Tl[l], l, cur_mp->log2Ml[l], l, cur_mp->Ml[l]); +#endif + } + + return (0); +} + +/* */ + +void mbe_demodulateImbe7200x4400Data(char imbe[8][23]) +{ + int i, j, k; + unsigned short pr[115]; + unsigned short foo; + char tmpstr[24]; + + // create pseudo-random modulator + j = 0; + tmpstr[12] = 0; + for (i = 22; i >= 11; i--) { + tmpstr[j] = (imbe[0][i] + 48); + j++; + } + + foo = strtol(tmpstr, NULL, 2); + pr[0] = (16 * foo); + for (i = 1; i < 115; i++) { + pr[i] = (173 * pr[i - 1]) + 13849 - (65536 * (((173 * pr[i - 1]) + 13849) / 65536)); + } + + for (i = 1; i < 115; i++) { + pr[i] = pr[i] / 32768; + } + + // demodulate imbe with pr + k = 1; + for (i = 1; i < 4; i++) { + for (j = 22; j >= 0; j--) { + imbe[i][j] = ((imbe[i][j]) ^ pr[k]); + k++; + } + } + + for (i = 4; i < 7; i++) { + for (j = 14; j >= 0; j--) { + imbe[i][j] = ((imbe[i][j]) ^ pr[k]); + k++; + } + } +} + +/* */ + +void mbe_processImbe4400DataF(float* aout_buf, int* errs, int* errs2, char* err_str, char imbe_d[88], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality) +{ + int i, bad; + + for (i = 0; i < *errs2; i++) { + *err_str = '='; + err_str++; + } + + bad = mbe_decodeImbe4400Parms(imbe_d, cur_mp, prev_mp); + if ((bad == 1) || (*errs2 > 5)) { + mbe_useLastMbeParms(cur_mp, prev_mp); + cur_mp->repeat++; + *err_str = 'R'; + err_str++; + } + else { + cur_mp->repeat = 0; + } + + if (cur_mp->repeat <= 3) { + mbe_moveMbeParms(cur_mp, prev_mp); + mbe_spectralAmpEnhance(cur_mp); + mbe_synthesizeSpeechF(aout_buf, cur_mp, prev_mp_enhanced, uvquality); + mbe_moveMbeParms(cur_mp, prev_mp_enhanced); + } + else { + *err_str = 'M'; + err_str++; + mbe_synthesizeSilenceF(aout_buf); + mbe_initMbeParms(cur_mp, prev_mp, prev_mp_enhanced); + } + *err_str = 0; +} + +/* */ + +void mbe_processImbe4400Data(short* aout_buf, int* errs, int* errs2, char* err_str, char imbe_d[88], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality) +{ + float float_buf[160]; + mbe_processImbe4400DataF(float_buf, errs, errs2, err_str, imbe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality); + mbe_floatToShort(float_buf, aout_buf); +} + +/* */ + +void mbe_processImbe7200x4400FrameF(float* aout_buf, int* errs, int* errs2, char* err_str, char imbe_fr[8][23], char imbe_d[88], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality) +{ + *errs = 0; + *errs2 = 0; + *errs = mbe_eccImbe7200x4400C0(imbe_fr); + mbe_demodulateImbe7200x4400Data(imbe_fr); + *errs2 = *errs; + *errs2 += mbe_eccImbe7200x4400Data(imbe_fr, imbe_d); + + mbe_processImbe4400DataF(aout_buf, errs, errs2, err_str, imbe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality); +} + +/* */ + +void mbe_processImbe7200x4400Frame(short* aout_buf, int* errs, int* errs2, char* err_str, char imbe_fr[8][23], char imbe_d[88], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality) +{ + float float_buf[160]; + mbe_processImbe7200x4400FrameF(float_buf, errs, errs2, err_str, imbe_fr, imbe_d, cur_mp, prev_mp, prev_mp_enhanced, uvquality); + mbe_floatToShort(float_buf, aout_buf); +} diff --git a/vocoder/imbe7200x4400_const.h b/vocoder/imbe7200x4400_const.h new file mode 100644 index 0000000..51360ea --- /dev/null +++ b/vocoder/imbe7200x4400_const.h @@ -0,0 +1,920 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - MBE Vocoder + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + */ +/** + * @file imbe7200x4400_const.h + * @ingroup vocoder + */ + +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#if !defined(__IMBE7200x4400_CONST_H__) +#define __IMBE7200x4400_CONST_H__ + +#ifdef _MSC_VER +#pragma warning(disable: 4305) +#endif +#if defined(__GNUC__) || defined(__GNUG__) +#pragma GCC diagnostic ignored "-Wmissing-braces" +#endif + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +/* + * Quantizer step size for higher order DCT coefficients + */ +const float quantstep[11] = { + 1.2, 0.85, 0.65, 0.40, 0.28, 0.15, 0.08, 0.04, 0.02, 0.01 +}; + +/* + * Standard Dev. for higer order DCT coefficients + */ +const float standdev[9] = { + 0.307, 0.241, 0.207, 0.190, 0.179, 0.173, 0.165, 0.170, 0.170 +}; + +/* + * + */ +const float B2[64] = { + -2.842205, -2.694235, -2.558260, -2.382850, + -2.221042, -2.095574, -1.980845, -1.836058, + -1.645556, -1.417658, -1.261301, -1.125631, + -0.958207, -0.781591, -0.555837, -0.346976, + -0.147249, 0.027755, 0.211495, 0.388380, + 0.552873, 0.737223, 0.932197, 1.139032, + 1.320955, 1.483433, 1.648297, 1.801447, + 1.942731, 2.118613, 2.321486, 2.504443, + 2.653909, 2.780654, 2.925355, 3.076390, + 3.220825, 3.402869, 3.585096, 3.784606, + 3.955521, 4.155636, 4.314009, 4.444150, + 4.577542, 4.735552, 4.909493, 5.085264, + 5.254767, 5.411894, 5.568094, 5.738523, + 5.919215, 6.087701, 6.280685, 6.464201, + 6.647736, 6.834672, 7.022583, 7.211777, + 7.471016, 7.738948, 8.124863, 8.695827 +}; + +/* + * bit allocation and step size for transformed gain vector + */ +const float ba[48][5][2] = { + // L=9 + {{10, 0.003100}, {9, 0.004020}, {9, 0.003360}, {9, 0.002900}, {9, 0.002640}}, + // L=10 + {{9, 0.006200}, {9, 0.004020}, {8, 0.006720}, {8, 0.005800}, {8, 0.005280}}, + // L=11 + {{8, 0.012400}, {8, 0.008040}, {8, 0.006720}, {7, 0.011600}, {7, 0.010560}}, + // L=12 + {{8, 0.012400}, {7, 0.016080}, {7, 0.013440}, {7, 0.011600}, {7, 0.010560}}, + // L=13 + {{7, 0.024800}, {7, 0.016080}, {7, 0.013440}, {6, 0.021750}, {6, 0.019800}}, + // L=14 + {{7, 0.024800}, {6, 0.030150}, {6, 0.025200}, {6, 0.021750}, {6, 0.019800}}, + // L=15 + {{7, 0.024800}, {6, 0.030150}, {6, 0.025200}, {6, 0.021750}, {5, 0.036960}}, + // L=16 + {{6, 0.046500}, {6, 0.030150}, {6, 0.025200}, {5, 0.040600}, {5, 0.036960}}, + // L=17 + {{6, 0.046500}, {6, 0.030150}, {5, 0.047040}, {5, 0.040600}, {5, 0.036960}}, + // L=18 + {{6, 0.046500}, {5, 0.056280}, {5, 0.047040}, {5, 0.040600}, {5, 0.036960}}, + // L=19 + {{6, 0.046500}, {5, 0.056280}, {5, 0.047040}, {4, 0.058000}, {4, 0.052800}}, + // L=20 + {{6, 0.046500}, {5, 0.056280}, {5, 0.047040}, {4, 0.058000}, {4, 0.052800}}, + // L=21 + {{5, 0.086800}, {5, 0.056280}, {5, 0.047040}, {4, 0.058000}, {4, 0.052800}}, + // L=22 + {{5, 0.086800}, {5, 0.056280}, {4, 0.067200}, {4, 0.058000}, {4, 0.052800}}, + // L=23 + {{5, 0.086800}, {4, 0.080400}, {4, 0.067200}, {4, 0.068000}, {4, 0.052800}}, + // L=24 + {{5, 0.086800}, {4, 0.080400}, {4, 0.067200}, {4, 0.058000}, {4, 0.052800}}, + // L=25 + {{5, 0.086800}, {4, 0.080400}, {4, 0.067200}, {4, 0.058000}, {3, 0.085800}}, + // L=26 + {{5, 0.086800}, {4, 0.080400}, {4, 0.067200}, {3, 0.094250}, {3, 0.085800}}, + // L=27 + {{5, 0.086800}, {4, 0.080400}, {4, 0.067200}, {3, 0.094250}, {3, 0.085800}}, + // L=28 + {{4, 0.124000}, {4, 0.080400}, {4, 0.067200}, {3, 0.094250}, {3, 0.085800}}, + // L=29 + {{4, 0.124000}, {4, 0.080400}, {4, 0.067200}, {3, 0.094250}, {3, 0.085800}}, + // L=30 + {{4, 0.124000}, {4, 0.080400}, {4, 0.067200}, {3, 0.094250}, {3, 0.085800}}, + // L=31 + {{4, 0.124000}, {4, 0.080400}, {3, 0.109200}, {3, 0.094250}, {3, 0.085800}}, + // L=32 + {{4, 0.124000}, {4, 0.080400}, {3, 0.109200}, {3, 0.094250}, {3, 0.085800}}, + // L=33 + {{4, 0.124000}, {3, 0.130650}, {3, 0.109200}, {3, 0.094250}, {3, 0.085800}}, + // L=34 + {{4, 0.124000}, {3, 0.130650}, {3, 0.109200}, {3, 0.094250}, {3, 0.085800}}, + // L=35 + {{4, 0.124000}, {3, 0.130650}, {3, 0.109200}, {3, 0.094250}, {3, 0.085800}}, + // L=36 + {{4, 0.124000}, {3, 0.130650}, {3, 0.109200}, {3, 0.094250}, {3, 0.085800}}, + // L=37 + {{4, 0.124000}, {3, 0.130650}, {3, 0.109200}, {3, 0.094250}, {2, 0.112200}}, + // L=38 + {{4, 0.124000}, {3, 0.130650}, {3, 0.109200}, {3, 0.094250}, {2, 0.112200}}, + // L=39 + {{4, 0.124000}, {3, 0.130650}, {3, 0.109200}, {3, 0.094250}, {2, 0.112200}}, + // L=40 + {{4, 0.124000}, {3, 0.130650}, {3, 0.109200}, {3, 0.094250}, {2, 0.112200}}, + // L=41 + {{4, 0.124000}, {3, 0.130650}, {3, 0.109200}, {2, 0.123250}, {2, 0.112200}}, + // L=42 + {{4, 0.124000}, {3, 0.130650}, {3, 0.109200}, {2, 0.123250}, {2, 0.112200}}, + // L=43 + {{4, 0.124000}, {3, 0.130650}, {3, 0.109200}, {2, 0.123250}, {2, 0.112200}}, + // L=44 + {{4, 0.124000}, {3, 0.130650}, {3, 0.109200}, {2, 0.123250}, {2, 0.112200}}, + // L=45 + {{4, 0.124000}, {3, 0.130650}, {3, 0.109200}, {2, 0.123250}, {2, 0.112200}}, + // L=46 + {{3, 0.201500}, {3, 0.130650}, {3, 0.109200}, {2, 0.123250}, {2, 0.112200}}, + // L=47 + {{3, 0.201500}, {3, 0.130650}, {3, 0.109200}, {2, 0.123250}, {2, 0.112200}}, + // L=48 + {{3, 0.201500}, {3, 0.130650}, {3, 0.109200}, {2, 0.123250}, {2, 0.112200}}, + // L=49 + {{3, 0.201500}, {3, 0.130650}, {3, 0.109200}, {2, 0.123250}, {2, 0.112200}}, + // L=50 + {{3, 0.201500}, {3, 0.130650}, {3, 0.109200}, {2, 0.123250}, {2, 0.112200}}, + // L=51 + {{3, 0.201500}, {3, 0.130650}, {3, 0.109200}, {2, 0.123250}, {2, 0.112200}}, + // L=52 + {{3, 0.201500}, {3, 0.130650}, {2, 0.142800}, {2, 0.123250}, {2, 0.112200}}, + // L=53 + {{3, 0.201500}, {3, 0.130650}, {2, 0.142800}, {2, 0.123250}, {2, 0.112200}}, + // L=54 + {{3, 0.201500}, {3, 0.130650}, {2, 0.142800}, {2, 0.123250}, {2, 0.112200}}, + // L=55 + {{3, 0.201500}, {3, 0.130650}, {2, 0.142800}, {2, 0.123250}, {2, 0.112200}}, + // L=56 + {{3, 0.201500}, {3, 0.130650}, {2, 0.142800}, {2, 0.123250}, {2, 0.112200}} +}; + +/* + * Bit allocation for higher Order DCT Coefficients + */ +const int hoba[48][50] = { + // L=9 + {9, 8, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=10 + {9, 7, 6, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=11 + {9, 7, 6, 5, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=12 + {8, 7, 6, 5, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=13 + {7, 7, 6, 5, 4, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=14 + {7, 7, 5, 4, 4, 3, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=15 + {6, 7, 5, 4, 4, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=16 + {6, 6, 5, 4, 4, 3, 3, 3, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=17 + {5, 5, 5, 4, 4, 4, 3, 3, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=18 + {5, 4, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=19 + {5, 4, 5, 4, 4, 3, 3, 3, 3, 2, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=20 + {5, 4, 5, 4, 4, 3, 3, 2, 3, 2, 1, 3, 2, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=21 + {4, 4, 5, 4, 4, 3, 3, 2, 2, 3, 2, 1, 3, 2, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=22 + {4, 4, 4, 4, 4, 3, 2, 3, 2, 2, 3, 2, 1, 2, 2, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=23 + {4, 3, 4, 4, 3, 4, 3, 2, 3, 2, 2, 2, 2, 1, 2, 2, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=24 + {4, 3, 3, 4, 3, 3, 3, 3, 2, 3, 2, 1, 2, 2, 1, 2, 2, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=25 + {4, 3, 3, 4, 3, 3, 3, 3, 2, 3, 2, 1, 2, 2, 1, 2, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=26 + {4, 3, 3, 4, 3, 3, 3, 2, 2, 3, 2, 1, 2, 2, 1, 1, 2, 2, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=27 + {4, 3, 2, 4, 3, 2, 3, 2, 2, 3, 2, 2, 1, 2, 2, 1, 1, 2, 2, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=28 + {4, 3, 2, 4, 3, 2, 3, 2, 2, 2, 3, 2, 1, 1, 2, 2, 1, 1, 2, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=29 + {3, 3, 2, 4, 3, 2, 2, 3, 2, 2, 2, 3, 2, 1, 1, 2, 1, 1, 1, 2, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=30 + {3, 3, 2, 2, 3, 3, 2, 2, 3, 2, 2, 1, 3, 2, 1, 1, 2, 1, 1, 1, + 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=31 + {3, 3, 2, 2, 3, 3, 2, 2, 3, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 1, + 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=32 + {3, 3, 2, 2, 3, 3, 2, 2, 3, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 1, + 1, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=33 + {3, 3, 2, 2, 3, 3, 2, 2, 3, 2, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, + 1, 1, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=34 + {3, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 1, 1, 2, 2, 1, 1, 1, 2, 1, + 1, 1, 1, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=35 + {3, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, + 1, 1, 1, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=36 + {3, 2, 2, 2, 1, 3, 2, 2, 2, 1, 3, 2, 1, 1, 1, 2, 2, 1, 1, 1, + 2, 1, 1, 1, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=37 + {3, 2, 2, 2, 1, 3, 2, 2, 2, 2, 3, 2, 1, 1, 1, 2, 1, 1, 1, 1, + 2, 1, 1, 1, 0, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=38 + {3, 2, 2, 2, 1, 3, 2, 2, 2, 1, 3, 2, 1, 1, 1, 2, 1, 1, 1, 1, + 2, 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=39 + {3, 2, 2, 2, 1, 3, 2, 2, 2, 1, 3, 2, 1, 1, 1, 2, 2, 1, 1, 1, + 0, 2, 1, 1, 1, 1, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=40 + {3, 2, 2, 2, 1, 3, 2, 2, 1, 1, 3, 2, 1, 1, 1, 1, 2, 2, 1, 1, + 1, 0, 2, 1, 1, 1, 1, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=41 + {3, 2, 2, 1, 1, 3, 2, 2, 2, 1, 1, 3, 2, 1, 1, 1, 1, 2, 2, 1, + 1, 1, 0, 2, 1, 1, 1, 1, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=42 + {3, 2, 2, 2, 1, 1, 3, 2, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, + 1, 1, 1, 0, 2, 1, 1, 1, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=43 + {3, 2, 2, 2, 1, 1, 3, 2, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, + 1, 1, 1, 0, 2, 1, 1, 1, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=44 + {3, 2, 2, 1, 1, 1, 3, 2, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, + 1, 1, 1, 0, 2, 1, 1, 1, 1, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=45 + {3, 2, 2, 1, 1, 1, 3, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, + 1, 1, 1, 0, 0, 2, 1, 1, 1, 1, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=46 + {3, 2, 2, 1, 1, 1, 3, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, + 2, 1, 1, 1, 0, 0, 2, 1, 1, 1, 1, 0, 0, 2, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=47 + {3, 2, 2, 1, 1, 1, 3, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, + 2, 2, 1, 1, 1, 0, 0, 2, 1, 1, 1, 1, 0, 0, 2, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=48 + {3, 2, 2, 1, 1, 1, 1, 3, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, + 1, 2, 2, 1, 1, 1, 0, 0, 2, 1, 1, 1, 0, 0, 0, 2, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=49 + {3, 2, 2, 1, 1, 1, 1, 3, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, + 0, 2, 2, 1, 1, 1, 0, 0, 2, 1, 1, 1, 0, 0, 0, 2, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=50 + {3, 2, 2, 1, 1, 1, 1, 3, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, + 0, 2, 2, 1, 1, 1, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, 2, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=51 + {3, 2, 2, 1, 1, 1, 1, 3, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, + 0, 2, 2, 1, 1, 1, 0, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, 2, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}, + // L=52 + {3, 2, 1, 1, 1, 1, 1, 3, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, + 1, 0, 2, 2, 1, 1, 1, 0, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, 2, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, + // L=53 + {3, 2, 1, 1, 1, 1, 1, 3, 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, + 1, 1, 0, 2, 2, 1, 1, 1, 0, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, 2, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, + // L=54 + {3, 2, 2, 1, 1, 1, 1, 0, 3, 2, 2, 1, 1, 1, 1, 0, 2, 2, 1, 1, + 1, 1, 1, 0, 2, 2, 1, 1, 1, 0, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, + 2, 1, 1, 1, 0, 0, 0, 0, 0, 0}, + // L=55 + {3, 2, 2, 1, 1, 1, 1, 0, 3, 2, 2, 1, 1, 1, 1, 0, 2, 2, 1, 1, + 1, 1, 1, 0, 2, 2, 1, 1, 1, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, + 2, 1, 1, 1, 1, 0, 0, 0, 0, 0}, + // L=56 + {3, 2, 2, 1, 1, 1, 1, 0, 3, 2, 2, 1, 1, 1, 1, 0, 2, 2, 1, 1, + 1, 1, 1, 0, 2, 2, 1, 1, 1, 0, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, + 0, 2, 1, 1, 1, 0, 0, 0, 0, 0} +}; + + +/* + * bit order for reading data out of imbe data + */ + +const int bo[48][79][2] = { + // L=9 + 2, 5, 2, 4, 2, 3, 3, 9, 3, 8, 4, 8, + 5, 8, 6, 8, 7, 8, 8, 8, 3, 7, 4, 7, 5, 7, 6, 7, 7, 7, 8, 7, 9, 7, 3, 6, + 4, 6, 5, 6, 6, 6, 7, 6, 8, 6, 9, 6, 10, 6, 3, 5, 4, 5, 5, 5, 6, 5, 7, 5, + 8, 5, 9, 5, 10, 5, 3, 4, 4, 4, 5, 4, 6, 4, 7, 4, 8, 4, 9, 4, 10, 4, 3, 3, + 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, 4, 3, 5, 3, 6, 3, 7, 3, 8, 3, 9, 3, + 10, 3, 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, 10, 2, 3, 1, 4, 1, + 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, + 8, 0, 9, 0, 10, 0, 2, 0, + + // L=10 + 2, 5, 2, 4, 2, 3, 3, 8, 4, 8, 8, 8, + 3, 7, 4, 7, 5, 7, 6, 7, 7, 7, 8, 7, 3, 6, 4, 6, 5, 6, 6, 6, 7, 6, 8, 6, + 9, 6, 3, 5, 4, 5, 5, 5, 6, 5, 7, 5, 8, 5, 9, 5, 10, 5, 3, 4, 4, 4, 5, 4, + 6, 4, 7, 4, 8, 4, 9, 4, 10, 4, 11, 4, 3, 3, 4, 3, 5, 3, 6, 3, 7, 3, 8, 3, + 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, 9, 3, 10, 3, 11, 3, 3, 2, 4, 2, + 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, 10, 2, 11, 2, 3, 1, 4, 1, 5, 1, 6, 1, + 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, + 9, 0, 10, 0, 11, 0, 2, 0, + + // L=11 + 2, 5, 2, 4, 2, 3, 8, 8, 3, 7, 4, 7, + 5, 7, 8, 7, 3, 6, 4, 6, 5, 6, 6, 6, 7, 6, 8, 6, 9, 6, 3, 5, 4, 5, 5, 5, + 6, 5, 7, 5, 8, 5, 9, 5, 10, 5, 3, 4, 4, 4, 5, 4, 6, 4, 7, 4, 8, 4, 9, 4, + 10, 4, 11, 4, 3, 3, 4, 3, 5, 3, 6, 3, 7, 3, 8, 3, 9, 3, 10, 3, 11, 3, 12, 3, + 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, + 8, 2, 9, 2, 10, 2, 11, 2, 12, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, + 9, 1, 10, 1, 11, 1, 12, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, + 10, 0, 11, 0, 12, 0, 2, 0, + + // L=12 + 2, 5, 2, 4, 2, 3, 3, 7, 8, 7, 3, 6, + 4, 6, 5, 6, 6, 6, 7, 6, 8, 6, 9, 6, 3, 5, 4, 5, 5, 5, 6, 5, 7, 5, 8, 5, + 9, 5, 10, 5, 3, 4, 4, 4, 5, 4, 6, 4, 7, 4, 8, 4, 9, 4, 10, 4, 11, 4, 3, 3, + 4, 3, 5, 3, 6, 3, 7, 3, 8, 3, 9, 3, 10, 3, 11, 3, 12, 3, 3, 2, 4, 2, 5, 2, + 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, 6, 2, 7, 2, 8, 2, 9, 2, 10, 2, + 11, 2, 12, 2, 13, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, + 11, 1, 12, 1, 13, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, + 11, 0, 12, 0, 13, 0, 2, 0, + + // L=13 + 2, 5, 2, 4, 2, 3, 3, 6, 4, 6, 5, 6, + 8, 6, 9, 6, 3, 5, 4, 5, 5, 5, 6, 5, 7, 5, 8, 5, 9, 5, 10, 5, 3, 4, 4, 4, + 5, 4, 6, 4, 7, 4, 8, 4, 9, 4, 10, 4, 11, 4, 3, 3, 4, 3, 5, 3, 6, 3, 7, 3, + 8, 3, 9, 3, 10, 3, 11, 3, 12, 3, 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, + 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, 10, 2, 11, 2, 12, 2, 13, 2, + 14, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, + 13, 1, 14, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, + 12, 0, 13, 0, 14, 0, 2, 0, + + // L=14 + 2, 5, 2, 4, 2, 3, 3, 6, 8, 6, 9, 6, + 3, 5, 4, 5, 5, 5, 6, 5, 7, 5, 8, 5, 9, 5, 3, 4, 4, 4, 5, 4, 6, 4, 7, 4, + 8, 4, 9, 4, 10, 4, 3, 3, 4, 3, 5, 3, 6, 3, 7, 3, 8, 3, 9, 3, 10, 3, 11, 3, + 12, 3, 14, 3, 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, 10, 2, 11, 2, 12, 2, + 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, 13, 2, 14, 2, 15, 2, 3, 1, + 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, + 15, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, + 13, 0, 14, 0, 15, 0, 2, 0, + + // L=15 + 2, 5, 2, 4, 2, 3, 3, 6, 9, 6, 3, 5, + 4, 5, 5, 5, 6, 5, 8, 5, 9, 5, 3, 4, 4, 4, 5, 4, 6, 4, 7, 4, 8, 4, 9, 4, + 10, 4, 3, 3, 4, 3, 5, 3, 6, 3, 7, 3, 8, 3, 9, 3, 10, 3, 11, 3, 12, 3, 3, 2, + 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, 10, 2, 11, 2, 12, 2, 13, 2, 14, 2, 15, 2, + 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, 16, 2, 3, 1, 4, 1, 5, 1, + 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, 16, 1, + 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, + 14, 0, 15, 0, 16, 0, 2, 0, + + // L=16 + 2, 5, 2, 4, 2, 3, 3, 5, 4, 5, 5, 5, + 8, 5, 9, 5, 3, 4, 4, 4, 5, 4, 6, 4, 7, 4, 8, 4, 9, 4, 10, 4, 3, 3, 4, 3, + 5, 3, 6, 3, 7, 3, 8, 3, 9, 3, 10, 3, 11, 3, 12, 3, 3, 2, 4, 2, 5, 2, 6, 2, + 7, 2, 8, 2, 9, 2, 10, 2, 11, 2, 12, 2, 13, 2, 14, 2, 15, 2, 16, 2, 3, 1, 4, 1, + 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, 5, 1, 6, 1, 7, 1, + 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, 3, 0, + 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, + 15, 0, 16, 0, 17, 0, 2, 0, + + // L=17 + 2, 5, 2, 4, 2, 3, 3, 5, 4, 5, 3, 4, + 4, 4, 5, 4, 6, 4, 7, 4, 8, 4, 9, 4, 10, 4, 3, 3, 4, 3, 5, 3, 6, 3, 7, 3, + 8, 3, 9, 3, 10, 3, 11, 3, 12, 3, 13, 3, 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, + 9, 2, 10, 2, 11, 2, 12, 2, 13, 2, 14, 2, 15, 2, 17, 2, 3, 1, 4, 1, 5, 1, 6, 1, + 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, 7, 1, 8, 1, 9, 1, + 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, 18, 1, 3, 0, 4, 0, + 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, + 16, 0, 17, 0, 18, 0, 2, 0, + + // L=18 + 2, 5, 2, 4, 2, 3, 3, 5, 3, 4, 4, 4, + 5, 4, 6, 4, 7, 4, 8, 4, 10, 4, 11, 4, 3, 3, 4, 3, 5, 3, 6, 3, 7, 3, 8, 3, + 9, 3, 10, 3, 11, 3, 12, 3, 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, 10, 2, + 11, 2, 12, 2, 13, 2, 14, 2, 15, 2, 16, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, + 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, 9, 1, 10, 1, 11, 1, + 12, 1, 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, 18, 1, 19, 1, 3, 0, 4, 0, 5, 0, + 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, + 17, 0, 18, 0, 19, 0, 2, 0, + + // L=19 + 2, 5, 2, 4, 2, 3, 3, 5, 3, 4, 4, 4, + 5, 4, 8, 4, 10, 4, 3, 3, 4, 3, 5, 3, 6, 3, 7, 3, 8, 3, 9, 3, 10, 3, 11, 3, + 12, 3, 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, 10, 2, 11, 2, 12, 2, 13, 2, + 14, 2, 15, 2, 16, 2, 18, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, + 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, 11, 1, 12, 1, + 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, 18, 1, 19, 1, 3, 0, 4, 0, 5, 0, 6, 0, + 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, + 18, 0, 19, 0, 20, 0, 2, 0, + + // L=20 + 2, 5, 2, 4, 2, 3, 3, 5, 3, 4, 4, 4, + 5, 4, 8, 4, 10, 4, 3, 3, 4, 3, 5, 3, 6, 3, 7, 3, 8, 3, 9, 3, 10, 3, 11, 3, + 12, 3, 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, 10, 2, 11, 2, 12, 2, 13, 2, + 14, 2, 16, 2, 19, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, + 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, 12, 1, 13, 1, + 14, 1, 15, 1, 16, 1, 17, 1, 19, 1, 20, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, + 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, + 19, 0, 20, 0, 21, 0, 2, 0, + + // L=21 + 2, 5, 2, 4, 2, 3, 3, 4, 4, 4, 5, 4, + 10, 4, 3, 3, 4, 3, 5, 3, 6, 3, 7, 3, 8, 3, 9, 3, 10, 3, 11, 3, 12, 3, 3, 2, + 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, 10, 2, 11, 2, 12, 2, 13, 2, 14, 2, 17, 2, + 20, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, + 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, 14, 1, 15, 1, + 16, 1, 17, 1, 18, 1, 20, 1, 21, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, + 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, + 20, 0, 21, 0, 22, 0, 2, 0, + + // L=22 + 2, 5, 2, 4, 2, 3, 3, 4, 4, 4, 3, 3, + 4, 3, 5, 3, 6, 3, 7, 3, 8, 3, 9, 3, 10, 3, 11, 3, 12, 3, 3, 2, 4, 2, 5, 2, + 6, 2, 7, 2, 8, 2, 9, 2, 10, 2, 11, 2, 12, 2, 13, 2, 15, 2, 18, 2, 3, 1, 4, 1, + 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, 16, 1, + 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, 17, 1, + 18, 1, 19, 1, 21, 1, 22, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, + 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, + 21, 0, 22, 0, 23, 0, 2, 0, + + // L=23 + 2, 5, 2, 4, 2, 3, 3, 4, 3, 3, 4, 3, + 5, 3, 6, 3, 7, 3, 8, 3, 10, 3, 11, 3, 13, 3, 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, + 8, 2, 9, 2, 10, 2, 11, 2, 12, 2, 13, 2, 14, 2, 16, 2, 3, 1, 4, 1, 5, 1, 6, 1, + 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, 18, 1, + 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, 19, 1, + 20, 1, 22, 1, 23, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, + 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, + 22, 0, 23, 0, 24, 0, 2, 0, + + // L=24 + 2, 5, 2, 4, 2, 3, 3, 4, 3, 3, 4, 3, + 5, 3, 6, 3, 7, 3, 8, 3, 11, 3, 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, + 10, 2, 11, 2, 12, 2, 13, 2, 14, 2, 15, 2, 17, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, + 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, 18, 1, 20, 1, + 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, 21, 1, + 23, 1, 24, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, + 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, + 23, 0, 24, 0, 25, 0, 2, 0, + + // L=25 + 2, 5, 2, 4, 2, 3, 3, 4, 3, 3, 4, 3, + 5, 3, 6, 3, 8, 3, 11, 3, 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, 10, 2, + 11, 2, 12, 2, 13, 2, 14, 2, 15, 2, 17, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, + 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, 18, 1, 20, 1, 21, 1, + 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, + 23, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, + 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, + 24, 0, 25, 0, 26, 0, 2, 0, + + // L=26 + 2, 5, 2, 4, 2, 3, 3, 4, 3, 3, 4, 3, + 5, 3, 8, 3, 11, 3, 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, 10, 2, 11, 2, + 12, 2, 13, 2, 14, 2, 17, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, + 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, 18, 1, 20, 1, 21, 1, 24, 1, 25, 1, + 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, + 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, + 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, + 25, 0, 26, 0, 27, 0, 2, 0, + + // L=27 + 2, 5, 2, 4, 2, 3, 3, 4, 3, 3, 4, 3, + 5, 3, 8, 3, 11, 3, 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, 11, 2, 12, 2, + 14, 2, 17, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, + 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, 18, 1, 19, 1, 21, 1, 22, 1, 25, 1, 26, 1, 3, 0, + 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, 2, 1, + 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, + 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, + 26, 0, 27, 0, 28, 0, 2, 0, + + // L=28 + 2, 5, 2, 4, 2, 3, 3, 3, 4, 3, 5, 3, + 8, 3, 11, 3, 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, 11, 2, 12, 2, 14, 2, + 18, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, + 14, 1, 15, 1, 16, 1, 17, 1, 18, 1, 19, 1, 22, 1, 23, 1, 26, 1, 3, 0, 4, 0, 5, 0, + 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, + 2, 1, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, + 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, + 27, 0, 28, 0, 29, 0, 2, 0, + + // L=29 + 2, 5, 2, 4, 2, 3, 3, 3, 4, 3, 5, 3, + 11, 3, 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, 11, 2, 12, 2, 15, 2, 19, 2, + 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, + 15, 1, 16, 1, 17, 1, 18, 1, 19, 1, 20, 1, 23, 1, 27, 1, 3, 0, 4, 0, 5, 0, 6, 0, + 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, + 2, 1, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, + 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, + 28, 0, 29, 0, 30, 0, 2, 0, + + // L=30 + 2, 5, 2, 4, 2, 3, 3, 3, 4, 3, 5, 3, + 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, 12, 2, 13, 2, 16, 2, 20, 2, 3, 1, + 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, + 16, 1, 17, 1, 18, 1, 20, 1, 21, 1, 24, 1, 28, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, + 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, 2, 2, + 2, 1, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, + 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, + 29, 0, 30, 0, 31, 0, 2, 0, + + // L=31 + 2, 5, 2, 4, 2, 3, 3, 3, 4, 3, 3, 2, + 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, 12, 2, 13, 2, 16, 2, 3, 1, 4, 1, 5, 1, + 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, + 18, 1, 20, 1, 21, 1, 24, 1, 28, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, + 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, + 2, 2, 2, 1, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, + 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, + 30, 0, 31, 0, 32, 0, 2, 0, + + // L=32 + 2, 5, 2, 4, 2, 3, 3, 3, 4, 3, 3, 2, + 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, 12, 2, 13, 2, 16, 2, 3, 1, 4, 1, 5, 1, + 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, + 18, 1, 20, 1, 21, 1, 24, 1, 29, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, + 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, + 2, 2, 2, 1, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, + 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, + 30, 0, 31, 0, 32, 0, 2, 0, + + // L=33 + 2, 5, 2, 4, 2, 3, 3, 3, 3, 2, 4, 2, + 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, 12, 2, 13, 2, 16, 2, 3, 1, 4, 1, 5, 1, 6, 1, + 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, 20, 1, + 21, 1, 25, 1, 30, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, + 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, 1, 0, + 2, 2, 2, 1, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, + 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, + 32, 0, 33, 0, 34, 0, 2, 0, + + // L=34 + 2, 5, 2, 4, 2, 3, 3, 3, 3, 2, 4, 2, + 5, 2, 6, 2, 7, 2, 8, 2, 12, 2, 16, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, + 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, 18, 1, 21, 1, 22, 1, + 26, 1, 31, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, + 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, + 32, 0, 33, 0, 34, 0, 2, 0, + + // L=35 + 2, 5, 2, 4, 2, 3, 3, 3, 3, 2, 4, 2, + 5, 2, 6, 2, 7, 2, 8, 2, 12, 2, 17, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, + 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, 18, 1, 22, 1, 23, 1, + 27, 1, 32, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, + 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 32, 0, + 33, 0, 34, 0, 35, 0, 2, 0, + + // L=36 + 2, 5, 2, 4, 2, 3, 3, 3, 3, 2, 4, 2, + 5, 2, 6, 2, 7, 2, 8, 2, 13, 2, 18, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, + 9, 1, 10, 1, 11, 1, 13, 1, 14, 1, 15, 1, 16, 1, 18, 1, 19, 1, 23, 1, 24, 1, 28, 1, + 33, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, + 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, 33, 0, + 34, 0, 35, 0, 36, 0, 2, 0, + + // L=37 + 2, 5, 2, 4, 2, 3, 3, 3, 3, 2, 4, 2, + 5, 2, 6, 2, 8, 2, 13, 2, 18, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, + 10, 1, 11, 1, 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, 18, 1, 19, 1, 23, 1, 28, 1, 33, 1, + 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, + 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, 33, 0, 34, 0, + 35, 0, 36, 0, 37, 0, 2, 0, + + // L=38 + 2, 5, 2, 4, 2, 3, 3, 3, 3, 2, 4, 2, + 5, 2, 6, 2, 8, 2, 13, 2, 18, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, + 10, 1, 11, 1, 13, 1, 14, 1, 15, 1, 16, 1, 18, 1, 19, 1, 23, 1, 28, 1, 34, 1, 3, 0, + 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, + 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, 32, 0, 34, 0, 35, 0, + 36, 0, 37, 0, 38, 0, 2, 0, + + // L=39 + 2, 5, 2, 4, 2, 3, 3, 3, 3, 2, 4, 2, + 5, 2, 6, 2, 8, 2, 13, 2, 18, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, + 10, 1, 11, 1, 13, 1, 14, 1, 15, 1, 16, 1, 18, 1, 19, 1, 23, 1, 24, 1, 29, 1, 35, 1, + 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, + 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 29, 0, 30, 0, 31, 0, 32, 0, 33, 0, 35, 0, + 36, 0, 37, 0, 38, 0, 2, 0, + + // L=40 + 2, 5, 2, 4, 2, 3, 3, 3, 3, 2, 4, 2, + 5, 2, 6, 2, 8, 2, 13, 2, 18, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, + 10, 1, 11, 1, 13, 1, 14, 1, 15, 1, 18, 1, 19, 1, 24, 1, 25, 1, 30, 1, 36, 1, 3, 0, + 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, + 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 30, 0, 31, 0, 32, 0, 33, 0, 34, 0, 36, 0, + 37, 0, 38, 0, 39, 0, 2, 0, + + // L=41 + 2, 5, 2, 4, 2, 3, 3, 3, 3, 2, 4, 2, + 5, 2, 8, 2, 13, 2, 19, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, + 13, 1, 14, 1, 15, 1, 16, 1, 19, 1, 20, 1, 25, 1, 26, 1, 31, 1, 37, 1, 3, 0, 4, 0, + 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, + 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 31, 0, 32, 0, 33, 0, 34, 0, 35, 0, 37, 0, + 38, 0, 39, 0, 40, 0, 2, 0, + + // L=42 + 2, 5, 2, 4, 2, 3, 3, 3, 3, 2, 4, 2, + 5, 2, 8, 2, 14, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, + 14, 1, 15, 1, 16, 1, 17, 1, 20, 1, 21, 1, 26, 1, 27, 1, 32, 1, 38, 1, 3, 0, 4, 0, + 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, + 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 32, 0, 33, 0, 34, 0, 35, 0, 38, 0, + 39, 0, 40, 0, 41, 0, 2, 0, + + // L=43 + 2, 5, 2, 4, 2, 3, 3, 3, 3, 2, 4, 2, + 5, 2, 8, 2, 14, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, 1, + 14, 1, 15, 1, 16, 1, 17, 1, 20, 1, 21, 1, 26, 1, 32, 1, 38, 1, 3, 0, 4, 0, 5, 0, + 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, + 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 32, 0, 33, 0, 34, 0, 35, 0, 38, 0, 39, 0, + 40, 0, 41, 0, 42, 0, 2, 0, + + // L=44 + 2, 5, 2, 4, 2, 3, 3, 3, 3, 2, 4, 2, + 5, 2, 8, 2, 14, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 14, 1, + 15, 1, 16, 1, 17, 1, 20, 1, 21, 1, 26, 1, 32, 1, 39, 1, 3, 0, 4, 0, 5, 0, 6, 0, + 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, + 27, 0, 28, 0, 29, 0, 30, 0, 32, 0, 33, 0, 34, 0, 35, 0, 36, 0, 39, 0, 40, 0, + 41, 0, 42, 0, 43, 0, 2, 0, + + // L=45 + 2, 5, 2, 4, 2, 3, 3, 3, 3, 2, 4, 2, + 5, 2, 8, 2, 14, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 14, 1, + 15, 1, 16, 1, 20, 1, 21, 1, 26, 1, 27, 1, 33, 1, 40, 1, 3, 0, 4, 0, 5, 0, 6, 0, + 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, + 27, 0, 28, 0, 29, 0, 30, 0, 33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 40, 0, 41, 0, + 42, 0, 43, 0, 44, 0, 2, 0, + + // L=46 + 2, 5, 2, 4, 2, 3, 3, 2, 4, 2, 5, 2, + 8, 2, 14, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 14, 1, 15, 1, + 16, 1, 20, 1, 21, 1, 27, 1, 28, 1, 34, 1, 41, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, + 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, + 28, 0, 29, 0, 30, 0, 31, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38, 0, 41, 0, 42, 0, + 43, 0, 44, 0, 45, 0, 2, 0, + + // L=47 + 2, 5, 2, 4, 2, 3, 3, 2, 4, 2, 5, 2, + 8, 2, 14, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 14, 1, 15, 1, + 16, 1, 21, 1, 22, 1, 28, 1, 29, 1, 35, 1, 42, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, + 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, + 28, 0, 29, 0, 30, 0, 31, 0, 32, 0, 35, 0, 36, 0, 37, 0, 38, 0, 39, 0, 42, 0, + 43, 0, 44, 0, 45, 0, 2, 0, + + // L=48 + 2, 5, 2, 4, 2, 3, 3, 2, 4, 2, 5, 2, + 8, 2, 15, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 15, 1, 16, 1, + 17, 1, 22, 1, 23, 1, 29, 1, 30, 1, 36, 1, 43, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, + 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, + 28, 0, 29, 0, 30, 0, 31, 0, 32, 0, 33, 0, 36, 0, 37, 0, 38, 0, 39, 0, 43, 0, + 44, 0, 45, 0, 46, 0, 2, 0, + + // L=49 + 2, 5, 2, 4, 2, 3, 3, 2, 4, 2, 5, 2, + 8, 2, 15, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 15, 1, 16, 1, + 17, 1, 22, 1, 23, 1, 29, 1, 30, 1, 36, 1, 43, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, + 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, + 29, 0, 30, 0, 31, 0, 32, 0, 33, 0, 36, 0, 37, 0, 38, 0, 39, 0, 43, 0, 44, 0, + 45, 0, 46, 0, 47, 0, 2, 0, + + // L=50 + 2, 5, 2, 4, 2, 3, 3, 2, 4, 2, 5, 2, + 8, 2, 15, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 15, 1, 16, 1, + 17, 1, 22, 1, 23, 1, 29, 1, 30, 1, 36, 1, 44, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, + 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, + 29, 0, 30, 0, 31, 0, 32, 0, 33, 0, 36, 0, 37, 0, 38, 0, 39, 0, 40, 0, 44, 0, + 45, 0, 46, 0, 47, 0, 2, 0, + + // L=51 + 2, 5, 2, 4, 2, 3, 3, 2, 4, 2, 5, 2, + 8, 2, 15, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 15, 1, 16, 1, + 22, 1, 23, 1, 29, 1, 30, 1, 37, 1, 45, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, + 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 29, 0, + 30, 0, 31, 0, 32, 0, 33, 0, 37, 0, 38, 0, 39, 0, 40, 0, 41, 0, 45, 0, 46, 0, + 47, 0, 48, 0, 49, 0, 2, 0, + + // L=52 + 2, 5, 2, 4, 2, 3, 3, 2, 4, 2, 8, 2, + 15, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 15, 1, 16, 1, 17, 1, 22, 1, + 23, 1, 30, 1, 31, 1, 38, 1, 46, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, + 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 30, 0, + 31, 0, 32, 0, 33, 0, 34, 0, 38, 0, 39, 0, 40, 0, 41, 0, 42, 0, 46, 0, 47, 0, + 48, 0, 49, 0, 50, 0, 2, 0, + + // L=53 + 2, 5, 2, 4, 2, 3, 3, 2, 4, 2, 8, 2, + 15, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 15, 1, 16, 1, 17, 1, 23, 1, + 24, 1, 31, 1, 32, 1, 39, 1, 47, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, + 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, + 31, 0, 32, 0, 33, 0, 34, 0, 35, 0, 39, 0, 40, 0, 41, 0, 42, 0, 43, 0, 47, 0, + 48, 0, 49, 0, 50, 0, 2, 0, + + // L=54 + 2, 5, 2, 4, 2, 3, 3, 2, 4, 2, 8, 2, + 16, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 16, 1, 17, 1, 18, 1, + 24, 1, 25, 1, 32, 1, 33, 1, 40, 1, 48, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, + 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 22, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, + 32, 0, 33, 0, 34, 0, 35, 0, 36, 0, 40, 0, 41, 0, 42, 0, 43, 0, 44, 0, 48, 0, + 49, 0, 50, 0, 51, 0, 2, 0, + + // L=55 + 2, 5, 2, 4, 2, 3, 3, 2, 4, 2, 8, 2, + 16, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 16, 1, 17, 1, 18, 1, + 24, 1, 25, 1, 32, 1, 33, 1, 40, 1, 48, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, + 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 22, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, + 32, 0, 33, 0, 34, 0, 35, 0, 36, 0, 40, 0, 41, 0, 42, 0, 43, 0, 48, 0, 49, 0, + 50, 0, 51, 0, 52, 0, 2, 0, + + // L=56 + 2, 5, 2, 4, 2, 3, 3, 2, 4, 2, 8, 2, + 16, 2, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 16, 1, 17, 1, 18, 1, + 24, 1, 25, 1, 32, 1, 33, 1, 40, 1, 49, 1, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, + 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, + 1, 11, 1, 10, 1, 9, 1, 8, 1, 7, 1, 6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1, + 1, 0, 2, 2, 2, 1, 22, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, + 32, 0, 33, 0, 34, 0, 35, 0, 36, 0, 40, 0, 41, 0, 42, 0, 43, 0, 44, 0, 49, 0, + 50, 0, 51, 0, 52, 0, 2, 0 +}; + +/* + * log magnitude residual block lengths + */ +const int ImbeJi[48][6] = { + {1, 1, 1, 2, 2, 2}, + {1, 1, 2, 2, 2, 2}, + {1, 2, 2, 2, 2, 2}, + {2, 2, 2, 2, 2, 2}, + {2, 2, 2, 2, 2, 3}, + {2, 2, 2, 2, 3, 3}, + {2, 2, 2, 3, 3, 3}, + {2, 2, 3, 3, 3, 3}, + {2, 3, 3, 3, 3, 3}, + {3, 3, 3, 3, 3, 3}, + {3, 3, 3, 3, 3, 4}, + {3, 3, 3, 3, 4, 4}, + {3, 3, 3, 4, 4, 4}, + {3, 3, 4, 4, 4, 4}, + {3, 4, 4, 4, 4, 4}, + {4, 4, 4, 4, 4, 4}, + {4, 4, 4, 4, 4, 5}, + {4, 4, 4, 4, 5, 5}, + {4, 4, 4, 5, 5, 5}, + {4, 4, 5, 5, 5, 5}, + {4, 5, 5, 5, 5, 5}, + {5, 5, 5, 5, 5, 5}, + {5, 5, 5, 5, 5, 6}, + {5, 5, 5, 5, 6, 6}, + {5, 5, 5, 6, 6, 6}, + {5, 5, 6, 6, 6, 6}, + {5, 6, 6, 6, 6, 6}, + {6, 6, 6, 6, 6, 6}, + {6, 6, 6, 6, 6, 7}, + {6, 6, 6, 6, 7, 7}, + {6, 6, 6, 7, 7, 7}, + {6, 6, 7, 7, 7, 7}, + {6, 7, 7, 7, 7, 7}, + {7, 7, 7, 7, 7, 7}, + {7, 7, 7, 7, 7, 8}, + {7, 7, 7, 7, 8, 8}, + {7, 7, 7, 8, 8, 8}, + {7, 7, 8, 8, 8, 8}, + {7, 8, 8, 8, 8, 8}, + {8, 8, 8, 8, 8, 8}, + {8, 8, 8, 8, 8, 9}, + {8, 8, 8, 8, 9, 9}, + {8, 8, 8, 9, 9, 9}, + {8, 8, 9, 9, 9, 9}, + {8, 9, 9, 9, 9, 9}, + {9, 9, 9, 9, 9, 9}, + {9, 9, 9, 9, 9, 10}, + {9, 9, 9, 9, 10, 10} +}; + +#endif // __IMBE7200x4400_CONST_H__ diff --git a/vocoder/mbe.c b/vocoder/mbe.c new file mode 100644 index 0000000..b114212 --- /dev/null +++ b/vocoder/mbe.c @@ -0,0 +1,477 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - MBE Vocoder + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + */ + +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#define _USE_MATH_DEFINES +#include + +#include "mbe.h" +#include "mbe_const.h" + +#ifdef _MSC_VER +#pragma warning(disable: 4244) +#endif + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +/* A pseudo - random float between[0.0, 1.0]. */ + +static float mbe_rand() +{ + return ((float)rand() / (float)RAND_MAX); +} + +/* A pseudo-random float between [-pi, +pi]. */ + +static float mbe_rand_phase() +{ + return mbe_rand() * (((float)M_PI) * 2.0F) - ((float)M_PI); +} + +/* */ + +void mbe_moveMbeParms(mbe_parms* cur_mp, mbe_parms* prev_mp) +{ + int l; + + prev_mp->w0 = cur_mp->w0; + prev_mp->L = cur_mp->L; + prev_mp->K = cur_mp->K; // necessary? + prev_mp->Ml[0] = (float)0; + prev_mp->gamma = cur_mp->gamma; + prev_mp->repeat = cur_mp->repeat; + + for (l = 0; l <= 56; l++) { + prev_mp->Ml[l] = cur_mp->Ml[l]; + prev_mp->Vl[l] = cur_mp->Vl[l]; + prev_mp->log2Ml[l] = cur_mp->log2Ml[l]; + prev_mp->PHIl[l] = cur_mp->PHIl[l]; + prev_mp->PSIl[l] = cur_mp->PSIl[l]; + } +} + +/* */ + +void mbe_useLastMbeParms(mbe_parms* cur_mp, mbe_parms* prev_mp) +{ + int l; + + cur_mp->w0 = prev_mp->w0; + cur_mp->L = prev_mp->L; + cur_mp->K = prev_mp->K; // necessary? + cur_mp->Ml[0] = (float)0; + cur_mp->gamma = prev_mp->gamma; + cur_mp->repeat = prev_mp->repeat; + + for (l = 0; l <= 56; l++) { + cur_mp->Ml[l] = prev_mp->Ml[l]; + cur_mp->Vl[l] = prev_mp->Vl[l]; + cur_mp->log2Ml[l] = prev_mp->log2Ml[l]; + cur_mp->PHIl[l] = prev_mp->PHIl[l]; + cur_mp->PSIl[l] = prev_mp->PSIl[l]; + } +} + +/* */ + +void mbe_initMbeParms(mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced) +{ + int l; + + prev_mp->w0 = 0.09378; + prev_mp->L = 30; + prev_mp->K = 10; + prev_mp->gamma = (float)0; + + for (l = 0; l <= 56; l++) { + prev_mp->Ml[l] = (float)0; + prev_mp->Vl[l] = 0; + prev_mp->log2Ml[l] = (float)0; // log2 of 1 == 0 + prev_mp->PHIl[l] = (float)0; + prev_mp->PSIl[l] = (M_PI / (float)2); + } + + prev_mp->repeat = 0; + mbe_moveMbeParms(prev_mp, cur_mp); + mbe_moveMbeParms(prev_mp, prev_mp_enhanced); +} + +/* */ + +void mbe_spectralAmpEnhance(mbe_parms* cur_mp) +{ + + float Rm0, Rm1, R2m0, R2m1, Wl[57]; + int l; + float sum, gamma, M; + + Rm0 = 0; + Rm1 = 0; + for (l = 1; l <= cur_mp->L; l++) { + Rm0 = Rm0 + (cur_mp->Ml[l] * cur_mp->Ml[l]); + Rm1 = Rm1 + ((cur_mp->Ml[l] * cur_mp->Ml[l]) * cosf(cur_mp->w0 * (float)l)); + } + + R2m0 = (Rm0 * Rm0); + R2m1 = (Rm1 * Rm1); + + for (l = 1; l <= cur_mp->L; l++) { + if (cur_mp->Ml[l] != 0) { + Wl[l] = sqrtf(cur_mp->Ml[l]) * powf((((float)0.96 * M_PI * ((R2m0 + R2m1) - ((float)2 * Rm0 * Rm1 * cosf(cur_mp->w0 * (float)l)))) / (cur_mp->w0 * Rm0 * (R2m0 - R2m1))), (float)0.25); + + if ((8 * l) <= cur_mp->L) { + // ? + } + else if (Wl[l] > 1.2) { + cur_mp->Ml[l] = 1.2 * cur_mp->Ml[l]; + } + else if (Wl[l] < 0.5) { + cur_mp->Ml[l] = 0.5 * cur_mp->Ml[l]; + } + else { + cur_mp->Ml[l] = Wl[l] * cur_mp->Ml[l]; + } + } + } + + // generate scaling factor + sum = 0; + for (l = 1; l <= cur_mp->L; l++) { + M = cur_mp->Ml[l]; + if (M < 0) { + M = -M; + } + + sum += (M * M); + } + + if (sum == 0) { + gamma = (float)1.0; + } + else { + gamma = sqrtf(Rm0 / sum); + } + + // apply scaling factor + for (l = 1; l <= cur_mp->L; l++) { + cur_mp->Ml[l] = gamma * cur_mp->Ml[l]; + } +} + +/* */ + +void mbe_synthesizeSilenceF(float* aout_buf) +{ + int n; + float* aout_buf_p; + + aout_buf_p = aout_buf; + for (n = 0; n < 160; n++) { + *aout_buf_p = (float)0; + aout_buf_p++; + } +} + +/* */ + +void mbe_synthesizeSilence(short* aout_buf) +{ + int n; + short* aout_buf_p; + + aout_buf_p = aout_buf; + for (n = 0; n < 160; n++) { + *aout_buf_p = (short)0; + aout_buf_p++; + } +} + +/* */ + +void mbe_synthesizeSpeechF(float* aout_buf, mbe_parms* cur_mp, mbe_parms* prev_mp, int uvquality) +{ + + int i, l, n, maxl; + float* Ss, loguvquality; + float C1, C2, C3, C4; + //float deltaphil, deltawl, thetaln, aln; + int numUv; + float cw0, pw0, cw0l, pw0l; + float uvsine, uvrand, uvthreshold, uvthresholdf; + float uvstep, uvoffset; + float qfactor; + float rphase[64], rphase2[64]; + + const int N = 160; + + uvthresholdf = (float)2700; + uvthreshold = ((uvthresholdf * M_PI) / (float)4000); + + // voiced/unvoiced/gain settings + uvsine = (float)1.3591409 * M_E; + uvrand = (float)2.0; + + if ((uvquality < 1) || (uvquality > 64)) { + fprintf(stderr, "MBE: Error - uvquality must be within the range 1 - 64, setting to default value of 3"); + uvquality = 3; + } + + // calculate loguvquality + if (uvquality == 1) { + loguvquality = (float)1 / M_E; + } + else { + loguvquality = log((float)uvquality) / (float)uvquality; + } + + // calculate unvoiced step and offset values + uvstep = (float)1.0 / (float)uvquality; + qfactor = loguvquality; + uvoffset = (uvstep * (float)(uvquality - 1)) / (float)2; + + // count number of unvoiced bands + numUv = 0; + for (l = 1; l <= cur_mp->L; l++) { + if (cur_mp->Vl[l] == 0) { + numUv++; + } + } + + cw0 = cur_mp->w0; + pw0 = prev_mp->w0; + + // init aout_buf + Ss = aout_buf; + for (n = 0; n < N; n++) { + *Ss = (float)0; + Ss++; + } + + // eq 128 and 129 + if (cur_mp->L > prev_mp->L) { + maxl = cur_mp->L; + for (l = prev_mp->L + 1; l <= maxl; l++) { + prev_mp->Ml[l] = (float)0; + prev_mp->Vl[l] = 1; + } + } + else { + maxl = prev_mp->L; + for (l = cur_mp->L + 1; l <= maxl; l++) { + cur_mp->Ml[l] = (float)0; + cur_mp->Vl[l] = 1; + } + } + + // update PHIl from eq 139,140 + for (l = 1; l <= 56; l++) { + cur_mp->PSIl[l] = prev_mp->PSIl[l] + ((pw0 + cw0) * ((float)(l * N) / (float)2)); + if (l <= (int)(cur_mp->L / 4)) { + cur_mp->PHIl[l] = cur_mp->PSIl[l]; + } + else { + cur_mp->PHIl[l] = cur_mp->PSIl[l] + ((numUv * mbe_rand_phase()) / cur_mp->L); + } + } + + for (l = 1; l <= maxl; l++) { + cw0l = (cw0 * (float)l); + pw0l = (pw0 * (float)l); + if ((cur_mp->Vl[l] == 0) && (prev_mp->Vl[l] == 1)) { + Ss = aout_buf; + // init random phase + for (i = 0; i < uvquality; i++) { + rphase[i] = mbe_rand_phase(); + } + + for (n = 0; n < N; n++) { + C1 = 0; + // eq 131 + C1 = Ws[n + N] * prev_mp->Ml[l] * cosf((pw0l * (float)n) + prev_mp->PHIl[l]); + C3 = 0; + + // unvoiced multisine mix + for (i = 0; i < uvquality; i++) + { + C3 = C3 + cosf((cw0 * (float)n * ((float)l + ((float)i * uvstep) - uvoffset)) + rphase[i]); + if (cw0l > uvthreshold) + { + C3 = C3 + ((cw0l - uvthreshold) * uvrand * mbe_rand()); + } + } + C3 = C3 * uvsine * Ws[n] * cur_mp->Ml[l] * qfactor; + *Ss = *Ss + C1 + C3; + Ss++; + } + } + else if ((cur_mp->Vl[l] == 1) && (prev_mp->Vl[l] == 0)) { + Ss = aout_buf; + // init random phase + for (i = 0; i < uvquality; i++) { + rphase[i] = mbe_rand_phase(); + } + + for (n = 0; n < N; n++) { + C1 = 0; + // eq 132 + C1 = Ws[n] * cur_mp->Ml[l] * cosf((cw0l * (float)(n - N)) + cur_mp->PHIl[l]); + C3 = 0; + + // unvoiced multisine mix + for (i = 0; i < uvquality; i++) { + C3 = C3 + cosf((pw0 * (float)n * ((float)l + ((float)i * uvstep) - uvoffset)) + rphase[i]); + if (pw0l > uvthreshold) { + C3 = C3 + ((pw0l - uvthreshold) * uvrand * mbe_rand()); + } + } + C3 = C3 * uvsine * Ws[n + N] * prev_mp->Ml[l] * qfactor; + *Ss = *Ss + C1 + C3; + Ss++; + } + } + // else if (((cur_mp->Vl[l] == 1) || (prev_mp->Vl[l] == 1)) && ((l >= 8) || (fabsf (cw0 - pw0) >= ((float) 0.1 * cw0)))) + else if ((cur_mp->Vl[l] == 1) || (prev_mp->Vl[l] == 1)) { + Ss = aout_buf; + for (n = 0; n < N; n++) { + C1 = 0; + // eq 133-1 + C1 = Ws[n + N] * prev_mp->Ml[l] * cosf((pw0l * (float)n) + prev_mp->PHIl[l]); + C2 = 0; + // eq 133-2 + C2 = Ws[n] * cur_mp->Ml[l] * cosf((cw0l * (float)(n - N)) + cur_mp->PHIl[l]); + *Ss = *Ss + C1 + C2; + Ss++; + } + } +/* + // expensive and unnecessary? + else if ((cur_mp->Vl[l] == 1) || (prev_mp->Vl[l] == 1)) { + Ss = aout_buf; + // eq 137 + deltaphil = cur_mp->PHIl[l] - prev_mp->PHIl[l] - (((pw0 + cw0) * (float) (l * N)) / (float) 2); + // eq 138 + deltawl = ((float) 1 / (float) N) * (deltaphil - ((float) 2 * M_PI * (int) ((deltaphil + M_PI) / (M_PI * (float) 2)))); + + for (n = 0; n < N; n++) { + // eq 136 + thetaln = prev_mp->PHIl[l] + ((pw0l + deltawl) * (float) n) + (((cw0 - pw0) * ((float) (l * n * n)) / (float) (2 * N))); + // eq 135 + aln = prev_mp->Ml[l] + (((float) n / (float) N) * (cur_mp->Ml[l] - prev_mp->Ml[l])); + // eq 134 + *Ss = *Ss + (aln * cosf (thetaln)); + Ss++; + } + } +*/ + else + { + Ss = aout_buf; + // init random phase + for (i = 0; i < uvquality; i++) { + rphase[i] = mbe_rand_phase(); + } + + // init random phase + for (i = 0; i < uvquality; i++) { + rphase2[i] = mbe_rand_phase(); + } + + for (n = 0; n < N; n++) { + C3 = 0; + + // unvoiced multisine mix + for (i = 0; i < uvquality; i++) { + C3 = C3 + cosf((pw0 * (float)n * ((float)l + ((float)i * uvstep) - uvoffset)) + rphase[i]); + if (pw0l > uvthreshold) { + C3 = C3 + ((pw0l - uvthreshold) * uvrand * mbe_rand()); + } + } + + C3 = C3 * uvsine * Ws[n + N] * prev_mp->Ml[l] * qfactor; + C4 = 0; + + // unvoiced multisine mix + for (i = 0; i < uvquality; i++) { + C4 = C4 + cosf((cw0 * (float)n * ((float)l + ((float)i * uvstep) - uvoffset)) + rphase2[i]); + if (cw0l > uvthreshold) { + C4 = C4 + ((cw0l - uvthreshold) * uvrand * mbe_rand()); + } + } + + C4 = C4 * uvsine * Ws[n] * cur_mp->Ml[l] * qfactor; + *Ss = *Ss + C3 + C4; + Ss++; + } + } + } +} + +/* */ + +void mbe_synthesizeSpeech(short* aout_buf, mbe_parms* cur_mp, mbe_parms* prev_mp, int uvquality) +{ + float float_buf[160]; + + mbe_synthesizeSpeechF(float_buf, cur_mp, prev_mp, uvquality); + mbe_floatToShort(float_buf, aout_buf); +} + +/* */ + +void mbe_floatToShort(float* float_buf, short* aout_buf) +{ + short* aout_buf_p; + float* float_buf_p; + int i, again; + float audio; + + again = 7; + aout_buf_p = aout_buf; + float_buf_p = float_buf; + for (i = 0; i < 160; i++) + { + audio = again * *float_buf_p; + if (audio > 32760) + { +#ifdef MBE_DEBUG + fprintf(stderr, "MBE: audio clip : % f", audio); +#endif + audio = 32760; + } + else if (audio < -32760) + { +#ifdef MBE_DEBUG + fprintf(stderr, "MBE: audio clip : % f", audio); +#endif + audio = -32760; + } + *aout_buf_p = (short)(audio); + aout_buf_p++; + float_buf_p++; + } +} diff --git a/vocoder/mbe.h b/vocoder/mbe.h new file mode 100644 index 0000000..6bd81c9 --- /dev/null +++ b/vocoder/mbe.h @@ -0,0 +1,474 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - MBE Vocoder + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + */ +/** + * @file mbe.h + * @ingroup vocoder + * @file mbe.c + * @ingroup vocoder + * @file ecc.c + * @ingroup vocoder + * @file imbe7200x4200.c + * @ingroup vocoder + * @file ambe3600x2450.c + * @ingroup vocoder + * @file ambe3600x2250.c + * @ingroup vocoder + */ +#if !defined(__MBE_H__) +#define __MBE_H__ + +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +// taken from GCC /usr/include/math.h +#ifndef M_E +#define M_E 2.7182818284590452354 /* e */ +#endif +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#endif +#ifndef M_SQRT2 +#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +#endif + +// --------------------------------------------------------------------------- +// Structure Declaration +// --------------------------------------------------------------------------- + +struct mbe_parameters +{ + float w0; + int L; + int K; + int Vl[57]; + float Ml[57]; + float log2Ml[57]; + float PHIl[57]; + float PSIl[57]; + float gamma; + int un; + int repeat; +}; + +typedef struct mbe_parameters mbe_parms; + +// --------------------------------------------------------------------------- +// Structure Declaration +// --------------------------------------------------------------------------- + +struct mbe_tones +{ + int ID; + int AD; + int n; +}; + +typedef struct mbe_tones mbe_tone; + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- +/* +** Prototypes from ecc.c +*/ +/** + * @brief Helper to check MBE block golay. + * @param block + */ +void mbe_checkGolayBlock(long int* block); +/** + * @brief Helper to check Golay (23,12). + * @param[in] in + * @param[out] out + * @returns int + */ +int mbe_golay2312(char* in, char* out); +/** + * @brief Helper to check Hamming (15,11). + * @param[in] in + * @param[out] out + * @returns int + */ +int mbe_hamming1511(char* in, char* out); +/** + * @brief Helper to check Hamming (15,11). + * @param[in] in + * @param[out] out + * @returns int + */ +int mbe_7100x4400Hamming1511(char* in, char* out); + +/* +** Prototypes from ambe3600x2400.c +*/ +/** + * @brief + * @param ambe_fr AMBE frames. + * @returns int + */ +int mbe_eccAmbe3600x2400C0(char ambe_fr[4][24]); +/** + * @brief + * @param ambe_fr AMBE frames. + * @param ambe_d AMBE data. + * @returns int + */ +int mbe_eccAmbe3600x2400Data(char ambe_fr[4][24], char* ambe_d); +/** + * @brief + * @param ambe_d + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @returns int + */ +int mbe_decodeAmbe2400Parms(char* ambe_d, mbe_parms* cur_mp, mbe_parms* prev_mp); +/** + * @brief + * @param ambe_fr AMBE frames. + * @returns int + */ +void mbe_demodulateAmbe3600x2400Data(char ambe_fr[4][24]); +/** + * @brief + * @param[out] aout_buf Audio Output (in float samples) + * @param errs + * @param errs2 + * @param err_str + * @param ambe_d AMBE data. + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @param prev_mp_enhanced Previous MBE parameters. + * @param uvquality + * @returns int + */ +void mbe_processAmbe2400DataF(float* aout_buf, int* errs, int* errs2, char* err_str, char ambe_d[49], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality); +/** + * @brief + * @param[out] aout_buf Audio Output (in short samples) + * @param errs + * @param errs2 + * @param err_str + * @param ambe_d AMBE data. + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @param prev_mp_enhanced Previous MBE parameters. + * @param uvquality + * @returns int + */ +void mbe_processAmbe2400Data(short* aout_buf, int* errs, int* errs2, char* err_str, char ambe_d[49], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality); +/** + * @brief + * @param[out] aout_buf Audio Output (in float samples) + * @param errs + * @param errs2 + * @param err_str + * @param ambe_fr AMBE frames. + * @param ambe_d AMBE data. + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @param prev_mp_enhanced Previous MBE parameters. + * @param uvquality + * @returns int + */ +void mbe_processAmbe3600x2400FrameF(float* aout_buf, int* errs, int* errs2, char* err_str, char ambe_fr[4][24], char ambe_d[49], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality); +/** + * @brief + * @param[out] aout_buf Audio Output (in short samples) + * @param errs + * @param errs2 + * @param err_str + * @param ambe_fr AMBE frames. + * @param ambe_d AMBE data. + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @param prev_mp_enhanced Previous MBE parameters. + * @param uvquality + * @returns int + */ +void mbe_processAmbe3600x2400Frame(short* aout_buf, int* errs, int* errs2, char* err_str, char ambe_fr[4][24], char ambe_d[49], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality); + +/* +** Prototypes from ambe3600x2450.c +*/ +/** + * @brief + * @param ambe_fr AMBE frames. + * @returns int + */ +int mbe_eccAmbe3600x2450C0(char ambe_fr[4][24]); +/** + * @brief + * @param ambe_fr AMBE frames. + * @param ambe_d AMBE data. + * @returns int + */ +int mbe_eccAmbe3600x2450Data(char ambe_fr[4][24], char* ambe_d); +/** + * @brief + * @param ambe_d AMBE data. + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @returns int + */ +int mbe_decodeAmbe2450Parms(char* ambe_d, mbe_parms* cur_mp, mbe_parms* prev_mp); +/** + * @brief + * @param ambe_fr AMBE frames. + * @returns int + */ +void mbe_demodulateAmbe3600x2450Data(char ambe_fr[4][24]); +/** + * @brief + * @param[out] aout_buf Audio Output (in float samples) + * @param errs + * @param errs2 + * @param err_str + * @param ambe_d AMBE data. + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @param prev_mp_enhanced Previous MBE parameters. + * @param uvquality + * @returns int + */ +void mbe_processAmbe2450DataF(float* aout_buf, int* errs, int* errs2, char* err_str, char ambe_d[49], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality); +/** + * @brief + * @param[out] aout_buf Audio Output (in short samples) + * @param errs + * @param errs2 + * @param err_str + * @param ambe_d AMBE data. + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @param prev_mp_enhanced Previous MBE parameters. + * @param uvquality + * @returns int + */ +void mbe_processAmbe2450Data(short* aout_buf, int* errs, int* errs2, char* err_str, char ambe_d[49], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality); +/** + * @brief + * @param[out] aout_buf Audio Output (in float samples) + * @param errs + * @param errs2 + * @param err_str + * @param ambe_fr AMBE frames. + * @param ambe_d AMBE data. + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @param prev_mp_enhanced Previous MBE parameters. + * @param uvquality + * @returns int + */ +void mbe_processAmbe3600x2450FrameF(float* aout_buf, int* errs, int* errs2, char* err_str, char ambe_fr[4][24], char ambe_d[49], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality); +/** + * @brief + * @param[out] aout_buf Audio Output (in short samples) + * @param errs + * @param errs2 + * @param err_str + * @param ambe_fr AMBE frames. + * @param ambe_d AMBE data. + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @param prev_mp_enhanced Previous MBE parameters. + * @param uvquality + * @returns int + */ +void mbe_processAmbe3600x2450Frame(short* aout_buf, int* errs, int* errs2, char* err_str, char ambe_fr[4][24], char ambe_d[49], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality); + +/* +** Prototypes from ambe3600x2250.c +*/ +/** + * @brief + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @param b + * @returns int + */ +int mbe_dequantizeAmbe2250Parms(mbe_parms* cur_mp, mbe_parms* prev_mp, const int* b); +/** + * @brief + * @param tone + * @param u + * @returns int + */ +int mbe_dequantizeAmbeTone(mbe_tone* tone, const int* u); + +/* +** Prototypes from imbe7200x4400.c +*/ +/** + * @brief + * @param imbe_fr IMBE frames. + * @returns int + */ +int mbe_eccImbe7200x4400C0(char imbe_fr[8][23]); +/** + * @brief + * @param imbe_fr IMBE frames. + * @param imbe_d IMBE data. + * @returns int + */ +int mbe_eccImbe7200x4400Data(char imbe_fr[8][23], char* imbe_d); +/** + * @brief + * @param imbe_d IMBE data. + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @returns int + */ +int mbe_decodeImbe4400Parms(char* imbe_d, mbe_parms* cur_mp, mbe_parms* prev_mp); +/** + * @brief + * @param imbe_fr IMBE frames. + * @returns int + */ +void mbe_demodulateImbe7200x4400Data(char imbe_fr[8][23]); +/** + * @brief + * @param[out] aout_buf Audio Output (in float samples) + * @param errs + * @param errs2 + * @param err_str + * @param imbe_d IMBE data. + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @param prev_mp_enhanced Previous MBE parameters. + * @param uvquality + * @returns int + */ +void mbe_processImbe4400DataF(float* aout_buf, int* errs, int* errs2, char* err_str, char imbe_d[88], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality); +/** + * @brief + * @param[out] aout_buf Audio Output (in short samples) + * @param errs + * @param errs2 + * @param err_str + * @param imbe_d IMBE data. + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @param prev_mp_enhanced Previous MBE parameters. + * @param uvquality + * @returns int + */ +void mbe_processImbe4400Data(short* aout_buf, int* errs, int* errs2, char* err_str, char imbe_d[88], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality); +/** + * @brief + * @param[out] aout_buf Audio Output (in float samples) + * @param errs + * @param errs2 + * @param err_str + * @param imbe_fr IMBE frames. + * @param imbe_d IMBE data. + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @param prev_mp_enhanced Previous MBE parameters. + * @param uvquality + * @returns int + */ +void mbe_processImbe7200x4400FrameF(float* aout_buf, int* errs, int* errs2, char* err_str, char imbe_fr[8][23], char imbe_d[88], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality); +/** + * @brief + * @param[out] aout_buf Audio Output (in short samples) + * @param errs + * @param errs2 + * @param err_str + * @param imbe_fr IMBE frames. + * @param imbe_d IMBE data. + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @param prev_mp_enhanced Previous MBE parameters. + * @param uvquality + * @returns int + */ +void mbe_processImbe7200x4400Frame(short* aout_buf, int* errs, int* errs2, char* err_str, char imbe_fr[8][23], char imbe_d[88], mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced, int uvquality); + +/* +** Prototypes from mbe.c +*/ +/** + * @brief + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + */ +void mbe_moveMbeParms(mbe_parms* cur_mp, mbe_parms* prev_mp); +/** + * @brief + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + */ +void mbe_useLastMbeParms(mbe_parms* cur_mp, mbe_parms* prev_mp); +/** + * @brief + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @param prev_mp_enhanced Previous MBE parameters. + */ +void mbe_initMbeParms(mbe_parms* cur_mp, mbe_parms* prev_mp, mbe_parms* prev_mp_enhanced); +/** + * @brief + * @param cur_mp Current MBE parameters. + */ +void mbe_spectralAmpEnhance(mbe_parms* cur_mp); +/** + * @brief + * @param[out] aout_buf Audio Output (in float samples) + */ +void mbe_synthesizeSilenceF(float* aout_buf); +/** + * @brief + * @param[out] aout_buf Audio Output (in short samples) + */ +void mbe_synthesizeSilence(short* aout_buf); +/** + * @brief + * @param[out] aout_buf Audio Output (in float samples) + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @param uvquality + */ +void mbe_synthesizeSpeechF(float* aout_buf, mbe_parms* cur_mp, mbe_parms* prev_mp, int uvquality); +/** + * @brief + * @param[out] aout_buf Audio Output (in short samples) + * @param cur_mp Current MBE parameters. + * @param prev_mp Previous MBE parameters. + * @param uvquality + */ +void mbe_synthesizeSpeech(short* aout_buf, mbe_parms* cur_mp, mbe_parms* prev_mp, int uvquality); +/** + * @brief + * @param[in] float_buf Audio (in short samples) + * @param[out] aout_buf Audio (in short samples) + */ +void mbe_floatToShort(float* float_buf, short* aout_buf); + +#ifdef __cplusplus +} +#endif + +#endif // __MBE_H__ diff --git a/vocoder/mbe_const.h b/vocoder/mbe_const.h new file mode 100644 index 0000000..7736ea7 --- /dev/null +++ b/vocoder/mbe_const.h @@ -0,0 +1,390 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - MBE Vocoder + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + */ +/** + * @file mbe_const.h + * @ingroup vocoder + */ + +/* + * Copyright (C) 2010 mbelib Author + * GPG Key ID: 0xEA5EFE2C (9E7A 5527 9CDC EBF7 BF1B D772 4F98 E863 EA5E FE2C) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#if !defined(__MBELIB_CONST_H__) +#define __MBELIB_CONST_H__ + +#ifdef _MSC_VER +#pragma warning(disable: 4305) +#endif + + // --------------------------------------------------------------------------- + // Constants + // --------------------------------------------------------------------------- + +/* + * Speech Synthesis Window 8k version + */ +const float Ws[321] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0.02, 0.04, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, + 0.2, 0.22, 0.24, 0.26, 0.28, 0.3, 0.32, 0.34, 0.36, 0.38, + 0.4, 0.42, 0.44, 0.46, 0.48, 0.5, 0.52, 0.54, 0.56, 0.58, + 0.6, 0.62, 0.64, 0.66, 0.68, 0.7, 0.72, 0.74, 0.76, 0.78, + 0.8, 0.82, 0.84, 0.86, 0.88, 0.9, 0.92, 0.94, 0.96, 0.98, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0.98, 0.96, 0.94, 0.92, 0.9, 0.88, 0.86, 0.84, 0.82, 0.8, + 0.78, 0.76, 0.74, 0.72, 0.7, 0.68, 0.66, 0.64, 0.62, 0.6, + 0.58, 0.56, 0.54, 0.52, 0.5, 0.48, 0.46, 0.44, 0.42, 0.4, + 0.38, 0.36, 0.34, 0.32, 0.3, 0.28, 0.26, 0.24, 0.22, 0.2, + 0.18, 0.16, 0.14, 0.12, 0.1, 0.08, 0.06, 0.04, 0.02, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * Speech Synthesis Window, 48k version + */ +/* +const float Ws48k[1926] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0.000, 0.003, 0.007, + 0.010, 0.013, 0.017, + 0.020, 0.023, 0.027, + 0.030, 0.033, 0.037, + 0.040, 0.043, 0.047, + 0.050, 0.053, 0.057, + 0.060, 0.063, 0.067, + 0.070, 0.073, 0.077, + 0.080, 0.083, 0.087, + 0.090, 0.093, 0.097, + 0.100, 0.103, 0.107, + 0.110, 0.113, 0.117, + 0.120, 0.123, 0.127, + 0.130, 0.133, 0.137, + 0.140, 0.143, 0.147, + 0.150, 0.153, 0.157, + 0.160, 0.163, 0.167, + 0.170, 0.173, 0.177, + 0.180, 0.183, 0.187, + 0.190, 0.193, 0.197, + 0.200, 0.203, 0.207, + 0.210, 0.213, 0.217, + 0.220, 0.223, 0.227, + 0.230, 0.233, 0.237, + 0.240, 0.243, 0.247, + 0.250, 0.253, 0.257, + 0.260, 0.263, 0.267, + 0.270, 0.273, 0.277, + 0.280, 0.283, 0.287, + 0.290, 0.293, 0.297, + 0.300, 0.303, 0.307, + 0.310, 0.313, 0.317, + 0.320, 0.323, 0.327, + 0.330, 0.333, 0.337, + 0.340, 0.343, 0.347, + 0.350, 0.353, 0.357, + 0.360, 0.363, 0.367, + 0.370, 0.373, 0.377, + 0.380, 0.383, 0.387, + 0.390, 0.393, 0.397, + 0.400, 0.403, 0.407, + 0.410, 0.413, 0.417, + 0.420, 0.423, 0.427, + 0.430, 0.433, 0.437, + 0.440, 0.443, 0.447, + 0.450, 0.453, 0.457, + 0.460, 0.463, 0.467, + 0.470, 0.473, 0.477, + 0.480, 0.483, 0.487, + 0.490, 0.493, 0.497, + 0.500, 0.503, 0.507, + 0.510, 0.513, 0.517, + 0.520, 0.523, 0.527, + 0.530, 0.533, 0.537, + 0.540, 0.543, 0.547, + 0.550, 0.553, 0.557, + 0.560, 0.563, 0.567, + 0.570, 0.573, 0.577, + 0.580, 0.583, 0.587, + 0.590, 0.593, 0.597, + 0.600, 0.603, 0.607, + 0.610, 0.613, 0.617, + 0.620, 0.623, 0.627, + 0.630, 0.633, 0.637, + 0.640, 0.643, 0.647, + 0.650, 0.653, 0.657, + 0.660, 0.663, 0.667, + 0.670, 0.673, 0.677, + 0.680, 0.683, 0.687, + 0.690, 0.693, 0.697, + 0.700, 0.703, 0.707, + 0.710, 0.713, 0.717, + 0.720, 0.723, 0.727, + 0.730, 0.733, 0.737, + 0.740, 0.743, 0.747, + 0.750, 0.753, 0.757, + 0.760, 0.763, 0.767, + 0.770, 0.773, 0.777, + 0.780, 0.783, 0.787, + 0.790, 0.793, 0.797, + 0.800, 0.803, 0.807, + 0.810, 0.813, 0.817, + 0.820, 0.823, 0.827, + 0.830, 0.833, 0.837, + 0.840, 0.843, 0.847, + 0.850, 0.853, 0.857, + 0.860, 0.863, 0.867, + 0.870, 0.873, 0.877, + 0.880, 0.883, 0.887, + 0.890, 0.893, 0.897, + 0.900, 0.903, 0.907, + 0.910, 0.913, 0.917, + 0.920, 0.923, 0.927, + 0.930, 0.933, 0.937, + 0.940, 0.943, 0.947, + 0.950, 0.953, 0.957, + 0.960, 0.963, 0.967, + 0.970, 0.973, 0.977, + 0.980, 0.983, 0.987, + 0.990, 0.993, 0.997, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0.997, 0.993, 0.990, + 0.987, 0.983, 0.980, + 0.977, 0.973, 0.970, + 0.967, 0.963, 0.960, + 0.957, 0.953, 0.950, + 0.947, 0.943, 0.940, + 0.937, 0.933, 0.930, + 0.927, 0.923, 0.920, + 0.917, 0.913, 0.910, + 0.907, 0.903, 0.900, + 0.897, 0.893, 0.890, + 0.887, 0.883, 0.880, + 0.877, 0.873, 0.870, + 0.867, 0.863, 0.860, + 0.857, 0.853, 0.850, + 0.847, 0.843, 0.840, + 0.837, 0.833, 0.830, + 0.827, 0.823, 0.820, + 0.817, 0.813, 0.810, + 0.807, 0.803, 0.800, + 0.797, 0.793, 0.790, + 0.787, 0.783, 0.780, + 0.777, 0.773, 0.770, + 0.767, 0.763, 0.760, + 0.757, 0.753, 0.750, + 0.747, 0.743, 0.740, + 0.737, 0.733, 0.730, + 0.727, 0.723, 0.720, + 0.717, 0.713, 0.710, + 0.707, 0.703, 0.700, + 0.697, 0.693, 0.690, + 0.687, 0.683, 0.680, + 0.677, 0.673, 0.670, + 0.667, 0.663, 0.660, + 0.657, 0.653, 0.650, + 0.647, 0.643, 0.640, + 0.637, 0.633, 0.630, + 0.627, 0.623, 0.620, + 0.617, 0.613, 0.610, + 0.607, 0.603, 0.600, + 0.597, 0.593, 0.590, + 0.587, 0.583, 0.580, + 0.577, 0.573, 0.570, + 0.567, 0.563, 0.560, + 0.557, 0.553, 0.550, + 0.547, 0.543, 0.540, + 0.537, 0.533, 0.530, + 0.527, 0.523, 0.520, + 0.517, 0.513, 0.510, + 0.507, 0.503, 0.500, + 0.497, 0.493, 0.490, + 0.487, 0.483, 0.480, + 0.477, 0.473, 0.470, + 0.467, 0.463, 0.460, + 0.457, 0.453, 0.450, + 0.447, 0.443, 0.440, + 0.437, 0.433, 0.430, + 0.427, 0.423, 0.420, + 0.417, 0.413, 0.410, + 0.407, 0.403, 0.400, + 0.397, 0.393, 0.390, + 0.387, 0.383, 0.380, + 0.377, 0.373, 0.370, + 0.367, 0.363, 0.360, + 0.357, 0.353, 0.350, + 0.347, 0.343, 0.340, + 0.337, 0.333, 0.330, + 0.327, 0.323, 0.320, + 0.317, 0.313, 0.310, + 0.307, 0.303, 0.300, + 0.297, 0.293, 0.290, + 0.287, 0.283, 0.280, + 0.277, 0.273, 0.270, + 0.267, 0.263, 0.260, + 0.257, 0.253, 0.250, + 0.247, 0.243, 0.240, + 0.237, 0.233, 0.230, + 0.227, 0.223, 0.220, + 0.217, 0.213, 0.210, + 0.207, 0.203, 0.200, + 0.197, 0.193, 0.190, + 0.187, 0.183, 0.180, + 0.177, 0.173, 0.170, + 0.167, 0.163, 0.160, + 0.157, 0.153, 0.150, + 0.147, 0.143, 0.140, + 0.137, 0.133, 0.130, + 0.127, 0.123, 0.120, + 0.117, 0.113, 0.110, + 0.107, 0.103, 0.100, + 0.097, 0.093, 0.090, + 0.087, 0.083, 0.080, + 0.077, 0.073, 0.070, + 0.067, 0.063, 0.060, + 0.057, 0.053, 0.050, + 0.047, 0.043, 0.040, + 0.037, 0.033, 0.030, + 0.027, 0.023, 0.020, + 0.017, 0.013, 0.010, + 0.007, 0.003, 0.000, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +*/ + +#endif // __MBELIB_CONST_H__