/* * ResidualSpectrum.cpp * * Copyright 2019 HIMSA II K/S - www.himsa.dk. 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 "BitReader.hpp" #include 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