diff options
Diffstat (limited to 'system/embdrv/lc3_dec/Decoder/DecoderFrame.cpp')
-rw-r--r-- | system/embdrv/lc3_dec/Decoder/DecoderFrame.cpp | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/system/embdrv/lc3_dec/Decoder/DecoderFrame.cpp b/system/embdrv/lc3_dec/Decoder/DecoderFrame.cpp new file mode 100644 index 0000000000..5ce8ff8377 --- /dev/null +++ b/system/embdrv/lc3_dec/Decoder/DecoderFrame.cpp @@ -0,0 +1,420 @@ +/* + * DecoderFrame.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 "DecoderFrame.hpp" + +#include <cmath> +#include <cstring> + +#include "BitReader.hpp" + +namespace Lc3Dec { + +DecoderFrame::DecoderFrame(ResidualSpectrum& residualSpectrum_, + SpectralNoiseShaping& spectralNoiseShaping_, + PacketLossConcealment& packetLossConcealment_, + MdctDec& mdctDec_, const Lc3Config& lc3Config_, + uint16_t nbytes_) + : nbytes(nbytes_), + nbits(nbytes_ * 8), + lc3Config(lc3Config_), + tns_lpc_weighting( + (nbits < + ((lc3Config.N_ms == Lc3Config::FrameDuration::d10ms) ? 480 : 360)) + ? 1 + : 0), + sideInformation(lc3Config.NF, lc3Config.NE, lc3Config.Fs_ind), + arithmeticDec(lc3Config.NF, lc3Config.NE, + (nbits > (160 + lc3Config.Fs_ind * 160)) ? 512 : 0, + tns_lpc_weighting), + residualSpectrum(residualSpectrum_), + spectralNoiseShaping(spectralNoiseShaping_), + packetLossConcealment(packetLossConcealment_), + mdctDec(mdctDec_), + longTermPostfilter(lc3Config, nbits), + + datapoints(nullptr), + + frameN(0), + lastnz(0), + P_BW(0), + lsbMode(0), + gg_ind(0), + num_tns_filters(0), + pitch_present(0), + pitch_index(0), + ltpf_active(0), + F_NF(0), + ind_LF(0), + ind_HF(0), + Gind(0), + LS_indA(0), + LS_indB(0), + idxA(0), + idxB(0), + nf_seed(0), + zeroFrame(0), + gg_off(0), + X_hat_q_nf(nullptr), + X_hat_f(nullptr), + X_s_tns(nullptr), + X_hat_ss(nullptr), + x_hat_clip(nullptr) { + rc_order[0] = 0; + rc_order[1] = 0; + + X_hat_q_nf = new double[lc3Config.NE]; + X_hat_f = new double[lc3Config.NE]; + X_s_tns = new double[lc3Config.NE]; + X_hat_ss = new double[lc3Config.NE]; +} + +DecoderFrame::~DecoderFrame() { + if (nullptr != X_hat_q_nf) { + delete[] X_hat_q_nf; + } + if (nullptr != X_hat_f) { + delete[] X_hat_f; + } + if (nullptr != X_s_tns) { + delete[] X_s_tns; + } + if (nullptr != X_hat_ss) { + delete[] X_hat_ss; + } + if (nullptr != x_hat_clip) { + delete[] x_hat_clip; + } +} + +void DecoderFrame::linkPreviousFrame(DecoderFrame* previousFrame) { + if (nullptr != previousFrame) { + longTermPostfilter = previousFrame->longTermPostfilter; + frameN = previousFrame->frameN; + } +} + +void DecoderFrame::noiseFilling() { + // 3.4.4 Noise filling (d09r02_F2F) + // including extensions according to: + // section 3.4.4. Noise filling (d09r04) + // Noise filling is performed only when zeroFrame is 0. + for (int16_t k = 0; k < lc3Config.NE; k++) { + X_hat_q_nf[k] = residualSpectrum.X_hat_q_residual[k]; + } + if (0 == zeroFrame) { + // bandwidth(πππ€) + // NB WB SSWB SWB FB + //ππ€_π π‘ππ 80 160 240 320 400 + uint16_t bw_stop_table[5] = {80, 160, 240, 320, 400}; + uint16_t bw_stop = bw_stop_table[P_BW]; + if (lc3Config.N_ms == Lc3Config::FrameDuration::d7p5ms) { + bw_stop *= 3; + bw_stop /= 4; + } + + uint16_t NFstart = + (lc3Config.N_ms == Lc3Config::FrameDuration::d10ms) ? 24 : 18; + uint16_t NFwidth = + (lc3Config.N_ms == Lc3Config::FrameDuration::d10ms) ? 3 : 2; + + /* + πΏππΉ Μ = (8-πΉππΉ)/16; + for k=0..bw_stop-1 + if πΌππΉ(k)==1 + nf_seed = (13849+nf_seed*31821) & 0xFFFF; + if nf_seed<0x8000 + ππ Μ(π) = πΏππΉ Μ ; + else + ππ Μ(π) = βπΏππΉ Μ ; + */ + uint16_t nf_state = nf_seed; + double L_NF_hat = (8 - F_NF) / 16.0; + for (uint16_t k = 0; k < bw_stop; k++) { + /* + The indices for the relevant spectral coefficients are given by: + πΌππΉ (π) = { + 1 if 24 β€ π < ππ€_π π‘ππ πππ ππ Μ(π) == 0 πππ πππ π = π β 3. . min(ππ€π π‘ππ + β 1, π + 3) 0 otherwise # (109) where ππ€_π π‘ππ depends on the bandwidth + information (see Section 3.4.2.4) as defined in Table 3.17. + */ + uint8_t I_NF_k = 0; + if ((NFstart <= k) && (k < bw_stop)) { + uint16_t limit = + ((bw_stop - 1) < (k + NFwidth)) ? (bw_stop - 1) : (k + NFwidth); + I_NF_k = 1; + for (uint16_t i = k - NFwidth; i <= limit; i++) { + if (0 != residualSpectrum.X_hat_q_residual[i]) { + I_NF_k = 0; + break; + } + } + } + + if (1 == I_NF_k) { + nf_state = (13849 + nf_state * 31821) & 0xFFFF; + if (nf_state < 0x8000) { + X_hat_q_nf[k] = L_NF_hat; + } else { + X_hat_q_nf[k] = -L_NF_hat; + } + } + } + } +} + +void DecoderFrame::applyGlobalGain() { + // 3.4.5 Global gain (d09r02_F2F) + // The global gain is applied to the spectrum after noise filling has been + // applied using the following formula (110) & (111) + int16_t v1 = nbits / (10 * (lc3Config.Fs_ind + 1)); + if (v1 > 115) { + gg_off = -115; + } else { + gg_off = -v1; + } + gg_off -= 105; + gg_off -= 5 * (lc3Config.Fs_ind + 1); + + double exponent = (gg_ind + gg_off) / 28.0; + double gg = pow(10.0, exponent); + for (int16_t k = 0; k < lc3Config.NE; k++) { + X_hat_f[k] = gg * X_hat_q_nf[k]; + } +} + +void DecoderFrame::temporalNoiseShaping() { + // 3.4.6 TNS DecoderFrame (d09r02_F2F) + /* + for π = 0 to ππΈ β 1 do { + ππ Μ(π) = ππ Μ(π) + } + s0 = s1 = s2 = s3 = s4 = s5 = s6 = s7 = 0 + for π = 0 to num_tns_filters-1 do { + if (πππππππ (π) > 0) + { + for π = start_freq(π) to stop_freq(f) β 1 do { + t = ππ Μ (π) β πππ (πππππππ (π) β 1 , π) β π πππππππ(π)β1 + for π = πππππππ (π) β 2 to 0 do { + π‘ = π‘ β πππ (π, π) β π π + π π+1 = πππ (π, π) β π‘ + π π + } + ππ Μ(π) = π‘ + π 0 = π‘ + } + } + } + */ + uint16_t start_freq[2] = {12, 160}; + uint16_t stop_freq[2]; + if (lc3Config.N_ms == Lc3Config::FrameDuration::d10ms) { + if (4 == P_BW) start_freq[1] = 200; + switch (P_BW) { + case 0: + stop_freq[0] = 80; + break; + case 1: + stop_freq[0] = 160; + break; + case 2: + stop_freq[0] = 240; + break; + case 3: + stop_freq[0] = 160; + stop_freq[1] = 320; + break; + case 4: + stop_freq[0] = 200; + stop_freq[1] = 400; + break; + } + } else { + start_freq[0] = 9; + if (3 == P_BW) start_freq[1] = 120; // Errata 15098 implemented + if (4 == P_BW) start_freq[1] = 150; + switch (P_BW) { + case 0: + stop_freq[0] = 60; + break; + case 1: + stop_freq[0] = 120; + break; + case 2: + stop_freq[0] = 180; + break; + case 3: + // stop_freq[0] = 119; // this value is specified in Table 3.19 + // (d09r06_KLG_AY_NH_FhG, 2019-12-20), but gives poor match to 32kHz + // decoder tests compared to reference decoder + stop_freq[0] = 120; // this value gives good match to reference decoder + // and is more consistent to 10ms case + stop_freq[1] = 240; + break; + case 4: + stop_freq[0] = 150; + stop_freq[1] = 300; + break; + } + } + + for (int16_t k = 0; k < lc3Config.NE; k++) { + X_s_tns[k] = X_hat_f[k]; + } + double s[8]; + for (uint8_t k = 0; k < 8; k++) { + s[k] = 0.0; + } + for (uint8_t f = 0; f < num_tns_filters; f++) { + if (arithmeticDec.rc_order_ari[f] > 0) { + for (uint16_t n = start_freq[f]; n < stop_freq[f]; n++) { + double t = X_hat_f[n] - + arithmeticDec.rc_q(arithmeticDec.rc_order_ari[f] - 1, f) * + s[arithmeticDec.rc_order_ari[f] - 1]; + for (int8_t k = arithmeticDec.rc_order_ari[f] - 2; k >= 0; k--) { + t = t - arithmeticDec.rc_q(k, f) * s[k]; + s[k + 1] = arithmeticDec.rc_q(k, f) * t + s[k]; + } + X_s_tns[n] = t; + s[0] = t; + } + } + } +} + +void DecoderFrame::runFloat(const uint8_t* bytes, uint8_t BFI, + uint8_t& BEC_detect) { + // increment frame counter + frameN++; + + // 5.4.2.2 Initialization + uint16_t bp = 0; + uint16_t bp_side = nbytes - 1; + uint8_t mask_side = 1; + BEC_detect = BFI; // Note: the base specification initializes BEC_detect with + // zero, but initialization with BFI is more meaningful + + // 5.4.2.3 Side information + if (!BEC_detect) { + sideInformation.run(bytes, bp_side, mask_side, P_BW, lastnz, lsbMode, + gg_ind, num_tns_filters, rc_order, pitch_present, + pitch_index, ltpf_active, F_NF, ind_LF, ind_HF, Gind, + LS_indA, LS_indB, idxA, idxB, BEC_detect); + } + + // 3.4.2.4 Bandwidth interpretation (d09r02_F2F) + // ...included somewhere else? + + // 3.4.2.5 Arithmetic decoding (d09r02_F2F) + if (!BEC_detect) { + arithmeticDec.run(bytes, bp, bp_side, mask_side, num_tns_filters, rc_order, + lsbMode, lastnz, nbits, BEC_detect); + } + + if (!BEC_detect) { + /* Decode residual bits */ + // and 3.4.3 Residual decoding (d09r02_F2F) + residualSpectrum.run(bytes, bp_side, mask_side, lastnz, + arithmeticDec.X_hat_q_ari, + arithmeticDec.nbits_residual, arithmeticDec.save_lev, + lsbMode, nf_seed, zeroFrame, gg_ind, F_NF); + + // 3.4.4 Noise filling (d09r02_F2F) + noiseFilling(); + + // 3.4.5 Global gain (d09r02_F2F) + applyGlobalGain(); + + // 3.4.6 TNS decoder (d09r02_F2F) + temporalNoiseShaping(); + + // 3.4.7 SNS decoder (d09r02_F2F) + spectralNoiseShaping.run( + X_s_tns, X_hat_ss, ind_LF, ind_HF, sideInformation.submodeMSB, + sideInformation.submodeLSB, Gind, LS_indA, LS_indB, idxA, idxB); + } + + // Appendix B. Packet Loss Concealment (d09r02_F2F) + packetLossConcealment.run(BEC_detect, X_hat_ss, ltpf_active); + + // 3.4.8 Low delay MDCT synthesis (d09r02_F2F) + mdctDec.run(X_hat_ss); + + // 3.4.9 Long Term Postfilter (d09r02_F2F) + if (0 == pitch_present) { + pitch_index = 0; + ltpf_active = 0; + } + longTermPostfilter.setInputX(mdctDec.x_hat_mdct); + longTermPostfilter.run(ltpf_active, pitch_index); +} + +void DecoderFrame::registerDatapoints(DatapointContainer* datapoints_) { + datapoints = datapoints_; + if (nullptr != datapoints) { + datapoints->addDatapoint("fs_idx", &lc3Config.Fs_ind, + sizeof(lc3Config.Fs_ind)); + + datapoints->addDatapoint("frameN", &frameN, sizeof(frameN)); + + datapoints->addDatapoint("lastnz", &lastnz, sizeof(lastnz)); + datapoints->addDatapoint("P_BW", &P_BW, sizeof(P_BW)); + datapoints->addDatapoint("lsbMode", &lsbMode, sizeof(lsbMode)); + datapoints->addDatapoint("gg_ind", &gg_ind, sizeof(gg_ind)); + datapoints->addDatapoint("num_tns_filters", &num_tns_filters, + sizeof(num_tns_filters)); + datapoints->addDatapoint("rc_order", &rc_order[0], sizeof(rc_order)); + datapoints->addDatapoint("pitch_index", &pitch_index, sizeof(pitch_index)); + datapoints->addDatapoint("pitch_present", &pitch_present, + sizeof(pitch_present)); + datapoints->addDatapoint("ltpf_active", <pf_active, sizeof(ltpf_active)); + datapoints->addDatapoint("F_NF", &F_NF, sizeof(F_NF)); + datapoints->addDatapoint("ind_LF", &ind_LF, sizeof(ind_LF)); + datapoints->addDatapoint("ind_HF", &ind_HF, sizeof(ind_HF)); + datapoints->addDatapoint("Gind", &Gind, sizeof(Gind)); + datapoints->addDatapoint("LS_indA", &LS_indA, sizeof(LS_indA)); + datapoints->addDatapoint("idxA", &idxA, sizeof(idxA)); + datapoints->addDatapoint("idxB", &idxB, sizeof(idxB)); + + datapoints->addDatapoint("nf_seed", &nf_seed, sizeof(nf_seed)); + datapoints->addDatapoint("zeroFrame", &zeroFrame, sizeof(zeroFrame)); + + datapoints->addDatapoint("gg_off", &gg_off, sizeof(gg_off)); + datapoints->addDatapoint("rc_i_tns", &arithmeticDec.rc_i[0], + sizeof(arithmeticDec.rc_i[0]) * 8); + + datapoints->addDatapoint("X_hat_q_nf", &X_hat_q_nf[0], + sizeof(double) * lc3Config.NE); + datapoints->addDatapoint("X_s_tns", &X_s_tns[0], + sizeof(double) * lc3Config.NE); + datapoints->addDatapoint("X_hat_ss", &X_hat_ss[0], + sizeof(double) * lc3Config.NE); + + if (nullptr == x_hat_clip) { + x_hat_clip = new double[lc3Config.NF]; + } + datapoints->addDatapoint("x_hat_clip", &x_hat_clip[0], + sizeof(double) * lc3Config.NF); + + sideInformation.registerDatapoints(datapoints); + arithmeticDec.registerDatapoints(datapoints); + longTermPostfilter.registerDatapoints(datapoints); + } +} + +} // namespace Lc3Dec |