blob: 55453ad32f8e4280542aa48264986279205dba1e [file] [log] [blame]
/*
* ResidualSpectrum.cpp
*
* Copyright 2021 HIMSA II K/S - www.himsa.com. Represented by EHIMA -
* www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ResidualSpectrum.hpp"
#include <cmath>
#include "BitReader.hpp"
namespace Lc3Dec {
ResidualSpectrum::ResidualSpectrum(uint16_t NE_)
: NE(NE_), X_hat_q_residual(nullptr), nResBits(0) {
X_hat_q_residual = new double[NE];
}
ResidualSpectrum::~ResidualSpectrum() { delete[] X_hat_q_residual; }
void ResidualSpectrum::run(
const uint8_t* bytes, uint16_t& bp_side, uint8_t& mask_side,
const uint16_t lastnz, const int16_t* const X_hat_q_ari,
uint16_t const nbits_residual, // the const is implementation dependent and
// thus not repeated in header declaration
uint8_t* save_lev, const uint8_t& lsbMode, uint16_t& nf_seed,
uint16_t& zeroFrame, const int16_t gg_ind, int16_t F_NF) {
// 3.4.2.6 Residual data and finalization (d09r02_F2F)
/* Decode residual bits */
for (uint16_t k = 0; k < lastnz; k++) {
X_hat_q_residual[k] = X_hat_q_ari[k];
}
// for (k = lastnz; k < 𝑁𝐸; k++)
for (uint16_t k = lastnz; k < NE; k++) {
//𝑋𝑞 ̂[k] = 0;
X_hat_q_residual[k] = 0;
}
uint8_t resBits[nbits_residual];
uint16_t remaining_nbits_residual =
nbits_residual; // changed relative to specification to ensure const
// input into array allocation
nResBits = 0;
if (lsbMode == 0) {
// for (k = 0; k < 𝑁𝐸; k++)
for (uint16_t k = 0; k < NE; k++) {
// if (𝑋𝑞 ̂[k] != 0)
if (X_hat_q_residual[k] != 0) {
if (nResBits == remaining_nbits_residual) {
break;
}
resBits[nResBits++] = read_bit(bytes, &bp_side, &mask_side);
}
}
} else {
for (uint16_t k = 0; k < lastnz; k += 2) {
if (save_lev[k] > 0) {
if (remaining_nbits_residual == 0) {
break;
}
uint8_t bit = read_bit(bytes, &bp_side, &mask_side);
remaining_nbits_residual--;
if (bit == 1) {
// if (𝑋𝑞 ̂[k] > 0)
if (X_hat_q_residual[k] > 0) {
//𝑋𝑞 ̂[k] += 1;
X_hat_q_residual[k] += 1;
}
// else if (𝑋𝑞 ̂[k] < 0)
else if (X_hat_q_residual[k] < 0) {
//𝑋𝑞 ̂[k] -= 1;
X_hat_q_residual[k] -= 1;
} else {
if (remaining_nbits_residual == 0) {
break;
}
bit = read_bit(bytes, &bp_side, &mask_side);
remaining_nbits_residual--;
if (bit == 0) {
//𝑋𝑞 ̂[k] = 1;
X_hat_q_residual[k] = 1;
} else {
//𝑋𝑞 ̂[k] = -1;
X_hat_q_residual[k] = -1;
}
}
}
if (remaining_nbits_residual == 0) {
break;
}
bit = read_bit(bytes, &bp_side, &mask_side);
remaining_nbits_residual--;
if (bit == 1) {
// if (𝑋𝑞 ̂[k+1] > 0)
if (X_hat_q_residual[k + 1] > 0) {
//𝑋𝑞 ̂[k+1] += 1;
X_hat_q_residual[k + 1] += 1;
}
// else if (𝑋𝑞 ̂[k+1] < 0)
else if (X_hat_q_residual[k + 1] < 0) {
//𝑋𝑞 ̂[k+1] -= 1;
X_hat_q_residual[k + 1] -= 1;
} else {
if (remaining_nbits_residual == 0) {
break;
}
bit = read_bit(bytes, &bp_side, &mask_side);
remaining_nbits_residual--;
if (bit == 0) {
//𝑋𝑞 ̂[k+1] = 1;
X_hat_q_residual[k + 1] = 1;
} else {
//𝑋𝑞 ̂[k+1] = -1;
X_hat_q_residual[k + 1] = -1;
}
}
}
}
}
}
/* Noise Filling Seed */
int16_t tmp = 0;
// for (k = 0; k < 𝑁𝐸; k++)
for (uint16_t k = 0; k < NE; k++) {
// tmp += abs(𝑋𝑞 ̂[k]) * k;
tmp += abs(X_hat_q_residual[k]) * k;
}
nf_seed = tmp & 0xFFFF; /* Note that both tmp and nf_seed are 32-bit int*/
/* Zero frame flag */
// if (lastnz == 2 && 𝑋𝑞 ̂[0] == 0 && 𝑋𝑞 ̂[1] == 0 && 𝑔𝑔𝑖𝑛𝑑 == 0 && 𝐹𝑁𝐹 == 7)
if ((lastnz == 2) && (X_hat_q_residual[0] == 0.0) &&
(X_hat_q_residual[1] == 0.0) && (gg_ind == 0) && (F_NF == 7)) {
zeroFrame = 1;
} else {
zeroFrame = 0;
}
// 3.4.3 Residual decoding (d09r02_F2F)
// Residual decoding is performed only when lsbMode is 0.
if (lsbMode == 0) {
uint16_t k, n;
k = n = 0;
// while (k < 𝑁𝐸 && n < nResBits)
while (k < NE && n < nResBits) {
// if (𝑋𝑞 ̂[k] != 0)
if (X_hat_q_residual[k] != 0) {
if (resBits[n++] == 0) {
// if (𝑋𝑞 ̂[k] > 0)
if (X_hat_q_residual[k] > 0) {
//𝑋𝑞 ̂[k] -= 0.1875;
X_hat_q_residual[k] -= 0.1875;
} else {
//𝑋𝑞 ̂[k] -= 0.3125;
X_hat_q_residual[k] -= 0.3125;
}
} else {
// if (𝑋𝑞 ̂[k] > 0)
if (X_hat_q_residual[k] > 0) {
//𝑋𝑞 ̂[k] += 0.3125;
X_hat_q_residual[k] += 0.3125;
} else {
//𝑋𝑞 ̂[k] += 0.1875;
X_hat_q_residual[k] += 0.1875;
}
}
}
k++;
}
}
}
void ResidualSpectrum::registerDatapoints(DatapointContainer* datapoints) {
if (nullptr != datapoints) {
datapoints->addDatapoint("X_hat_q_residual", &X_hat_q_residual[0],
sizeof(double) * NE);
}
}
} // namespace Lc3Dec