You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
758 lines
24 KiB
758 lines
24 KiB
// 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 <math.h>
|
|
|
|
/*
|
|
* 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 <cassert>
|
|
|
|
using namespace edac;
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(disable: 4244)
|
|
#endif
|
|
|
|
namespace vocoder {
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
// Extern methods for C#/C++ interop
|
|
MBEEncoder* MBEEncoder_Create(MBE_ENCODER_MODE mode)
|
|
{
|
|
return new MBEEncoder(mode);
|
|
}
|
|
|
|
void MBEEncoder_Encode(MBEEncoder* pEncoder, int16_t* samples, uint8_t* codeword)
|
|
{
|
|
if (pEncoder != NULL)
|
|
{
|
|
pEncoder->encode(samples, codeword);
|
|
}
|
|
}
|
|
|
|
void MBEEncoder_EncodeBits(MBEEncoder* pEncoder, uint8_t* bits, uint8_t* codeword)
|
|
{
|
|
if (pEncoder != NULL)
|
|
{
|
|
pEncoder->encodeBits(bits, codeword);
|
|
}
|
|
}
|
|
|
|
void MBEEncoder_Delete(MBEEncoder* pEncoder)
|
|
{
|
|
delete pEncoder;
|
|
pEncoder = NULL;
|
|
}
|
|
|
|
void Golay24128_Encode(uint8_t* data, const uint8_t* raw, uint32_t msglen)
|
|
{
|
|
Golay24128::encode24128(data, raw, msglen);
|
|
}
|
|
|
|
void Golay23127_Encode()
|
|
{
|
|
|
|
}
|
|
} // namespace vocoder
|