summaryrefslogtreecommitdiff
path: root/system/embdrv/lc3_dec/Decoder/DecoderFrame.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'system/embdrv/lc3_dec/Decoder/DecoderFrame.cpp')
-rw-r--r--system/embdrv/lc3_dec/Decoder/DecoderFrame.cpp420
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", &ltpf_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