summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/codecs/amrwb/src/dtx_decoder_amr_wb.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/codecs/amrwb/src/dtx_decoder_amr_wb.cpp')
-rw-r--r--media/libstagefright/codecs/amrwb/src/dtx_decoder_amr_wb.cpp984
1 files changed, 984 insertions, 0 deletions
diff --git a/media/libstagefright/codecs/amrwb/src/dtx_decoder_amr_wb.cpp b/media/libstagefright/codecs/amrwb/src/dtx_decoder_amr_wb.cpp
new file mode 100644
index 0000000..7c798cc
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/src/dtx_decoder_amr_wb.cpp
@@ -0,0 +1,984 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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.
+ * -------------------------------------------------------------------
+ */
+/****************************************************************************************
+Portions of this file are derived from the following 3GPP standard:
+
+ 3GPP TS 26.173
+ ANSI-C code for the Adaptive Multi-Rate - Wideband (AMR-WB) speech codec
+ Available from http://www.3gpp.org
+
+(C) 2007, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TTA, TTC)
+Permission to distribute, modify and use this file under the standard license
+terms listed above has been obtained from the copyright holder.
+****************************************************************************************/
+/*
+------------------------------------------------------------------------------
+
+
+
+ Filename: dtx_decoder_amr_wb.cpp
+
+ Date: 05/08/2007
+
+------------------------------------------------------------------------------
+ REVISION HISTORY
+
+
+ Description:
+
+------------------------------------------------------------------------------
+ INPUT AND OUTPUT DEFINITIONS
+
+
+------------------------------------------------------------------------------
+ FUNCTION DESCRIPTION
+
+ DTX functions
+
+------------------------------------------------------------------------------
+ REQUIREMENTS
+
+
+------------------------------------------------------------------------------
+ REFERENCES
+
+------------------------------------------------------------------------------
+ PSEUDO-CODE
+
+------------------------------------------------------------------------------
+*/
+
+
+/*----------------------------------------------------------------------------
+; INCLUDES
+----------------------------------------------------------------------------*/
+
+#include "pv_amr_wb_type_defs.h"
+#include "pvamrwbdecoder_basic_op.h"
+#include "pvamrwb_math_op.h"
+#include "pvamrwbdecoder_cnst.h"
+#include "pvamrwbdecoder_acelp.h" /* prototype of functions */
+#include "get_amr_wb_bits.h"
+#include "dtx.h"
+
+/*----------------------------------------------------------------------------
+; MACROS
+; Define module specific macros here
+----------------------------------------------------------------------------*/
+
+
+/*----------------------------------------------------------------------------
+; DEFINES
+; Include all pre-processor statements here. Include conditional
+; compile variables also.
+----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+; LOCAL FUNCTION DEFINITIONS
+; Function Prototype declaration
+----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+; LOCAL STORE/BUFFER/POINTER DEFINITIONS
+; Variable declaration - defined here and used outside this module
+----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+; EXTERNAL FUNCTION REFERENCES
+; Declare functions defined elsewhere and referenced in this module
+----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+; EXTERNAL GLOBAL STORE/BUFFER/POINTER REFERENCES
+; Declare variables used in this module but defined elsewhere
+----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+; FUNCTION CODE
+----------------------------------------------------------------------------*/
+/*
+ * Function : dtx_dec_amr_wb_reset
+ */
+int16 dtx_dec_amr_wb_reset(dtx_decState * st, const int16 isf_init[])
+{
+ int16 i;
+
+
+ if (st == (dtx_decState *) NULL)
+ {
+ /* dtx_dec_amr_wb_reset invalid parameter */
+ return (-1);
+ }
+ st->since_last_sid = 0;
+ st->true_sid_period_inv = (1 << 13); /* 0.25 in Q15 */
+
+ st->log_en = 3500;
+ st->old_log_en = 3500;
+ /* low level noise for better performance in DTX handover cases */
+
+ st->cng_seed = RANDOM_INITSEED;
+
+ st->hist_ptr = 0;
+
+ /* Init isf_hist[] and decoder log frame energy */
+ pv_memcpy((void *)st->isf, (void *)isf_init, M*sizeof(*isf_init));
+
+ pv_memcpy((void *)st->isf_old, (void *)isf_init, M*sizeof(*isf_init));
+
+ for (i = 0; i < DTX_HIST_SIZE; i++)
+ {
+ pv_memcpy((void *)&st->isf_hist[i * M], (void *)isf_init, M*sizeof(*isf_init));
+ st->log_en_hist[i] = st->log_en;
+ }
+
+ st->dtxHangoverCount = DTX_HANG_CONST;
+ st->decAnaElapsedCount = 32767;
+
+ st->sid_frame = 0;
+ st->valid_data = 0;
+ st->dtxHangoverAdded = 0;
+
+ st->dtxGlobalState = SPEECH;
+ st->data_updated = 0;
+
+ st->dither_seed = RANDOM_INITSEED;
+ st->CN_dith = 0;
+
+ return 0;
+}
+
+
+/*
+ Table of new SPD synthesis states
+
+ | previous SPD_synthesis_state
+ Incoming |
+ frame_type | SPEECH | DTX | DTX_MUTE
+ ---------------------------------------------------------------
+ RX_SPEECH_GOOD , | | |
+ RX_SPEECH_PR_DEGRADED | SPEECH | SPEECH | SPEECH
+ ----------------------------------------------------------------
+ RX_SPEECH_BAD, | SPEECH | DTX | DTX_MUTE
+ ----------------------------------------------------------------
+ RX_SID_FIRST, | DTX | DTX/(DTX_MUTE)| DTX_MUTE
+ ----------------------------------------------------------------
+ RX_SID_UPDATE, | DTX | DTX | DTX
+ ----------------------------------------------------------------
+ RX_SID_BAD, | DTX | DTX/(DTX_MUTE)| DTX_MUTE
+ ----------------------------------------------------------------
+ RX_NO_DATA, | SPEECH | DTX/(DTX_MUTE)| DTX_MUTE
+ RX_SPARE |(class2 garb.)| |
+ ----------------------------------------------------------------
+*/
+
+/*----------------------------------------------------------------------------
+; FUNCTION CODE
+----------------------------------------------------------------------------*/
+
+/*
+ * Function : dtx_dec_amr_wb
+ */
+int16 dtx_dec_amr_wb(
+ dtx_decState * st, /* i/o : State struct */
+ int16 * exc2, /* o : CN excitation */
+ int16 new_state, /* i : New DTX state */
+ int16 isf[], /* o : CN ISF vector */
+ int16 ** prms
+)
+{
+ int16 log_en_index;
+ int16 ind[7];
+ int16 i, j;
+ int16 int_fac;
+ int16 gain;
+
+ int32 L_isf[M], L_log_en_int, level32, ener32;
+ int16 ptr;
+ int16 tmp_int_length;
+ int16 tmp, exp, exp0, log_en_int_e, log_en_int_m, level;
+
+ /* This function is called if synthesis state is not SPEECH the globally passed inputs to this function
+ * are st->sid_frame st->valid_data st->dtxHangoverAdded new_state (SPEECH, DTX, DTX_MUTE) */
+
+ if ((st->dtxHangoverAdded != 0) &&
+ (st->sid_frame != 0))
+ {
+ /* sid_first after dtx hangover period */
+ /* or sid_upd after dtxhangover */
+
+ /* consider twice the last frame */
+ ptr = st->hist_ptr + 1;
+
+ if (ptr == DTX_HIST_SIZE)
+ ptr = 0;
+
+ pv_memcpy((void *)&st->isf_hist[ptr * M], (void *)&st->isf_hist[st->hist_ptr * M], M*sizeof(*st->isf_hist));
+
+ st->log_en_hist[ptr] = st->log_en_hist[st->hist_ptr];
+
+ /* compute mean log energy and isf from decoded signal (SID_FIRST) */
+ st->log_en = 0;
+ for (i = 0; i < M; i++)
+ {
+ L_isf[i] = 0;
+ }
+
+ /* average energy and isf */
+ for (i = 0; i < DTX_HIST_SIZE; i++)
+ {
+ /* Division by DTX_HIST_SIZE = 8 has been done in dtx_buffer log_en is in Q10 */
+ st->log_en = add_int16(st->log_en, st->log_en_hist[i]);
+
+ for (j = 0; j < M; j++)
+ {
+ L_isf[j] = add_int32(L_isf[j], (int32)(st->isf_hist[i * M + j]));
+ }
+ }
+
+ /* st->log_en in Q9 */
+ st->log_en >>= 1;
+
+ /* Add 2 in Q9, in order to have only positive values for Pow2 */
+ /* this value is subtracted back after Pow2 function */
+ st->log_en += 1024;
+
+ if (st->log_en < 0)
+ st->log_en = 0;
+
+ for (j = 0; j < M; j++)
+ {
+ st->isf[j] = (int16)(L_isf[j] >> 3); /* divide by 8 */
+ }
+
+ }
+
+ if (st->sid_frame != 0)
+ {
+ /* Set old SID parameters, always shift */
+ /* even if there is no new valid_data */
+
+ pv_memcpy((void *)st->isf_old, (void *)st->isf, M*sizeof(*st->isf));
+
+ st->old_log_en = st->log_en;
+
+ if (st->valid_data != 0) /* new data available (no CRC) */
+ {
+ /* st->true_sid_period_inv = 1.0f/st->since_last_sid; */
+ /* Compute interpolation factor, since the division only works * for values of since_last_sid <
+ * 32 we have to limit the * interpolation to 32 frames */
+ tmp_int_length = st->since_last_sid;
+
+
+ if (tmp_int_length > 32)
+ {
+ tmp_int_length = 32;
+ }
+
+ if (tmp_int_length >= 2)
+ {
+ st->true_sid_period_inv = div_16by16(1 << 10, shl_int16(tmp_int_length, 10));
+ }
+ else
+ {
+ st->true_sid_period_inv = 1 << 14; /* 0.5 it Q15 */
+ }
+
+ ind[0] = Serial_parm(6, prms);
+ ind[1] = Serial_parm(6, prms);
+ ind[2] = Serial_parm(6, prms);
+ ind[3] = Serial_parm(5, prms);
+ ind[4] = Serial_parm(5, prms);
+
+ Disf_ns(ind, st->isf);
+
+ log_en_index = Serial_parm(6, prms);
+
+ /* read background noise stationarity information */
+ st->CN_dith = Serial_parm_1bit(prms);
+
+ /* st->log_en = (float)log_en_index / 2.625 - 2.0; */
+ /* log2(E) in Q9 (log2(E) lies in between -2:22) */
+ st->log_en = shl_int16(log_en_index, 15 - 6);
+
+ /* Divide by 2.625 */
+ st->log_en = mult_int16(st->log_en, 12483);
+ /* Subtract 2 in Q9 is done later, after Pow2 function */
+
+ /* no interpolation at startup after coder reset */
+ /* or when SID_UPD has been received right after SPEECH */
+
+ if ((st->data_updated == 0) || (st->dtxGlobalState == SPEECH))
+ {
+ pv_memcpy((void *)st->isf_old, (void *)st->isf, M*sizeof(*st->isf));
+
+ st->old_log_en = st->log_en;
+ }
+ } /* endif valid_data */
+ } /* endif sid_frame */
+
+
+ if ((st->sid_frame != 0) && (st->valid_data != 0))
+ {
+ st->since_last_sid = 0;
+ }
+ /* Interpolate SID info */
+ int_fac = shl_int16(st->since_last_sid, 10); /* Q10 */
+ int_fac = mult_int16(int_fac, st->true_sid_period_inv); /* Q10 * Q15 -> Q10 */
+
+ /* Maximize to 1.0 in Q10 */
+
+ if (int_fac > 1024)
+ {
+ int_fac = 1024;
+ }
+ int_fac = shl_int16(int_fac, 4); /* Q10 -> Q14 */
+
+ L_log_en_int = mul_16by16_to_int32(int_fac, st->log_en); /* Q14 * Q9 -> Q24 */
+
+ for (i = 0; i < M; i++)
+ {
+ isf[i] = mult_int16(int_fac, st->isf[i]);/* Q14 * Q15 -> Q14 */
+ }
+
+ int_fac = 16384 - int_fac; /* 1-k in Q14 */
+
+ /* ( Q14 * Q9 -> Q24 ) + Q24 -> Q24 */
+ L_log_en_int = mac_16by16_to_int32(L_log_en_int, int_fac, st->old_log_en);
+
+ for (i = 0; i < M; i++)
+ {
+ /* Q14 + (Q14 * Q15 -> Q14) -> Q14 */
+ isf[i] = add_int16(isf[i], mult_int16(int_fac, st->isf_old[i]));
+ isf[i] = shl_int16(isf[i], 1); /* Q14 -> Q15 */
+ }
+
+ /* If background noise is non-stationary, insert comfort noise dithering */
+ if (st->CN_dith != 0)
+ {
+ CN_dithering(isf, &L_log_en_int, &st->dither_seed);
+ }
+ /* L_log_en_int corresponds to log2(E)+2 in Q24, i.e log2(gain)+1 in Q25 */
+ /* Q25 -> Q16 */
+ L_log_en_int >>= 9;
+
+ /* Find integer part */
+ log_en_int_e = extract_h(L_log_en_int);
+
+ /* Find fractional part */
+ log_en_int_m = (int16)(sub_int32(L_log_en_int, L_deposit_h(log_en_int_e)) >> 1);
+
+ /* Subtract 2 from L_log_en_int in Q9, i.e divide the gain by 2 (energy by 4) */
+ /* Add 16 in order to have the result of pow2 in Q16 */
+ log_en_int_e += 15;
+
+ /* level = (float)( pow( 2.0f, log_en ) ); */
+ level32 = power_of_2(log_en_int_e, log_en_int_m); /* Q16 */
+
+ exp0 = normalize_amr_wb(level32);
+ level32 <<= exp0; /* level in Q31 */
+ exp0 = 15 - exp0;
+ level = (int16)(level32 >> 16); /* level in Q15 */
+
+ /* generate white noise vector */
+ for (i = 0; i < L_FRAME; i++)
+ {
+ exc2[i] = noise_gen_amrwb(&(st->cng_seed)) >> 4;
+ }
+
+ /* gain = level / sqrt(ener) * sqrt(L_FRAME) */
+
+ /* energy of generated excitation */
+ ener32 = Dot_product12(exc2, exc2, L_FRAME, &exp);
+
+ one_ov_sqrt_norm(&ener32, &exp);
+
+ gain = extract_h(ener32);
+
+ gain = mult_int16(level, gain); /* gain in Q15 */
+
+ exp += exp0;
+
+ /* Multiply by sqrt(L_FRAME)=16, i.e. shift left by 4 */
+ exp += 4;
+
+ for (i = 0; i < L_FRAME; i++)
+ {
+ tmp = mult_int16(exc2[i], gain); /* Q0 * Q15 */
+ exc2[i] = shl_int16(tmp, exp);
+ }
+
+
+ if (new_state == DTX_MUTE)
+ {
+ /* mute comfort noise as it has been quite a long time since last SID update was performed */
+
+ tmp_int_length = st->since_last_sid;
+
+ if (tmp_int_length > 32)
+ {
+ tmp_int_length = 32;
+ }
+
+ st->true_sid_period_inv = div_16by16(1 << 10, shl_int16(tmp_int_length, 10));
+
+ st->since_last_sid = 0;
+ st->old_log_en = st->log_en;
+ /* subtract 1/8 in Q9 (energy), i.e -3/8 dB */
+ st->log_en -= 64;
+ }
+ /* reset interpolation length timer if data has been updated. */
+
+ if ((st->sid_frame != 0) &&
+ ((st->valid_data != 0) ||
+ ((st->valid_data == 0) && (st->dtxHangoverAdded) != 0)))
+ {
+ st->since_last_sid = 0;
+ st->data_updated = 1;
+ }
+ return 0;
+}
+
+
+/*----------------------------------------------------------------------------
+; FUNCTION CODE
+----------------------------------------------------------------------------*/
+
+void dtx_dec_amr_wb_activity_update(
+ dtx_decState * st,
+ int16 isf[],
+ int16 exc[])
+{
+ int16 i;
+
+ int32 L_frame_en;
+ int16 log_en_e, log_en_m, log_en;
+
+
+ st->hist_ptr++;
+
+ if (st->hist_ptr == DTX_HIST_SIZE)
+ {
+ st->hist_ptr = 0;
+ }
+ pv_memcpy((void *)&st->isf_hist[st->hist_ptr * M], (void *)isf, M*sizeof(*isf));
+
+
+ /* compute log energy based on excitation frame energy in Q0 */
+ L_frame_en = 0;
+ for (i = 0; i < L_FRAME; i++)
+ {
+ L_frame_en = mac_16by16_to_int32(L_frame_en, exc[i], exc[i]);
+ }
+ L_frame_en >>= 1;
+
+ /* log_en = (float)log10(L_frame_en/(float)L_FRAME)/(float)log10(2.0f); */
+ amrwb_log_2(L_frame_en, &log_en_e, &log_en_m);
+
+ /* convert exponent and mantissa to int16 Q7. Q7 is used to simplify averaging in dtx_enc */
+ log_en = shl_int16(log_en_e, 7); /* Q7 */
+ log_en += log_en_m >> 8;
+
+ /* Divide by L_FRAME = 256, i.e subtract 8 in Q7 = 1024 */
+ log_en -= 1024;
+
+ /* insert into log energy buffer */
+ st->log_en_hist[st->hist_ptr] = log_en;
+
+ return;
+}
+
+
+/*
+ Table of new SPD synthesis states
+
+ | previous SPD_synthesis_state
+ Incoming |
+ frame_type | SPEECH | DTX | DTX_MUTE
+ ---------------------------------------------------------------
+ RX_SPEECH_GOOD , | | |
+ RX_SPEECH_PR_DEGRADED | SPEECH | SPEECH | SPEECH
+ ----------------------------------------------------------------
+ RX_SPEECH_BAD, | SPEECH | DTX | DTX_MUTE
+ ----------------------------------------------------------------
+ RX_SID_FIRST, | DTX | DTX/(DTX_MUTE)| DTX_MUTE
+ ----------------------------------------------------------------
+ RX_SID_UPDATE, | DTX | DTX | DTX
+ ----------------------------------------------------------------
+ RX_SID_BAD, | DTX | DTX/(DTX_MUTE)| DTX_MUTE
+ ----------------------------------------------------------------
+ RX_NO_DATA, | SPEECH | DTX/(DTX_MUTE)| DTX_MUTE
+ RX_SPARE |(class2 garb.)| |
+ ----------------------------------------------------------------
+*/
+
+
+/*----------------------------------------------------------------------------
+; FUNCTION CODE
+----------------------------------------------------------------------------*/
+
+int16 rx_amr_wb_dtx_handler(
+ dtx_decState * st, /* i/o : State struct */
+ int16 frame_type /* i : Frame type */
+)
+{
+ int16 newState;
+ int16 encState;
+
+ /* DTX if SID frame or previously in DTX{_MUTE} and (NO_RX OR BAD_SPEECH) */
+
+
+
+ if ((frame_type == RX_SID_FIRST) ||
+ (frame_type == RX_SID_UPDATE) ||
+ (frame_type == RX_SID_BAD) ||
+ (((st->dtxGlobalState == DTX) ||
+ (st->dtxGlobalState == DTX_MUTE)) &&
+ ((frame_type == RX_NO_DATA) ||
+ (frame_type == RX_SPEECH_BAD) ||
+ (frame_type == RX_SPEECH_LOST))))
+ {
+ newState = DTX;
+
+ /* stay in mute for these input types */
+
+ if ((st->dtxGlobalState == DTX_MUTE) &&
+ ((frame_type == RX_SID_BAD) ||
+ (frame_type == RX_SID_FIRST) ||
+ (frame_type == RX_SPEECH_LOST) ||
+ (frame_type == RX_NO_DATA)))
+ {
+ newState = DTX_MUTE;
+ }
+ /* evaluate if noise parameters are too old */
+ /* since_last_sid is reset when CN parameters have been updated */
+ st->since_last_sid = add_int16(st->since_last_sid, 1);
+
+ /* no update of sid parameters in DTX for a long while */
+
+ if (st->since_last_sid > DTX_MAX_EMPTY_THRESH)
+ {
+ newState = DTX_MUTE;
+ }
+ }
+ else
+ {
+ newState = SPEECH;
+ st->since_last_sid = 0;
+ }
+
+ /* reset the decAnaElapsed Counter when receiving CNI data the first time, to robustify counter missmatch
+ * after handover this might delay the bwd CNI analysis in the new decoder slightly. */
+
+ if ((st->data_updated == 0) &&
+ (frame_type == RX_SID_UPDATE))
+ {
+ st->decAnaElapsedCount = 0;
+ }
+ /* update the SPE-SPD DTX hangover synchronization */
+ /* to know when SPE has added dtx hangover */
+ st->decAnaElapsedCount = add_int16(st->decAnaElapsedCount, 1);
+ st->dtxHangoverAdded = 0;
+
+
+ if ((frame_type == RX_SID_FIRST) ||
+ (frame_type == RX_SID_UPDATE) ||
+ (frame_type == RX_SID_BAD) ||
+ (frame_type == RX_NO_DATA))
+ {
+ encState = DTX;
+ }
+ else
+ {
+ encState = SPEECH;
+ }
+
+
+ if (encState == SPEECH)
+ {
+ st->dtxHangoverCount = DTX_HANG_CONST;
+ }
+ else
+ {
+
+ if (st->decAnaElapsedCount > DTX_ELAPSED_FRAMES_THRESH)
+ {
+ st->dtxHangoverAdded = 1;
+ st->decAnaElapsedCount = 0;
+ st->dtxHangoverCount = 0;
+ }
+ else if (st->dtxHangoverCount == 0)
+ {
+ st->decAnaElapsedCount = 0;
+ }
+ else
+ {
+ st->dtxHangoverCount--;
+ }
+ }
+
+ if (newState != SPEECH)
+ {
+ /* DTX or DTX_MUTE CN data is not in a first SID, first SIDs are marked as SID_BAD but will do
+ * backwards analysis if a hangover period has been added according to the state machine above */
+
+ st->sid_frame = 0;
+ st->valid_data = 0;
+
+
+ if (frame_type == RX_SID_FIRST)
+ {
+ st->sid_frame = 1;
+ }
+ else if (frame_type == RX_SID_UPDATE)
+ {
+ st->sid_frame = 1;
+ st->valid_data = 1;
+ }
+ else if (frame_type == RX_SID_BAD)
+ {
+ st->sid_frame = 1;
+ st->dtxHangoverAdded = 0; /* use old data */
+ }
+ }
+ return newState;
+ /* newState is used by both SPEECH AND DTX synthesis routines */
+}
+
+
+/*----------------------------------------------------------------------------
+; FUNCTION CODE
+----------------------------------------------------------------------------*/
+
+void aver_isf_history(
+ int16 isf_old[],
+ int16 indices[],
+ int32 isf_aver[]
+)
+{
+ int16 i, j, k;
+ int16 isf_tmp[2 * M];
+ int32 L_tmp;
+
+ /* Memorize in isf_tmp[][] the ISF vectors to be replaced by */
+ /* the median ISF vector prior to the averaging */
+ for (k = 0; k < 2; k++)
+ {
+
+ if (indices[k] + 1 != 0)
+ {
+ for (i = 0; i < M; i++)
+ {
+ isf_tmp[k * M + i] = isf_old[indices[k] * M + i];
+ isf_old[indices[k] * M + i] = isf_old[indices[2] * M + i];
+ }
+ }
+ }
+
+ /* Perform the ISF averaging */
+ for (j = 0; j < M; j++)
+ {
+ L_tmp = 0;
+
+ for (i = 0; i < DTX_HIST_SIZE; i++)
+ {
+ L_tmp = add_int32(L_tmp, (int32)(isf_old[i * M + j]));
+ }
+ isf_aver[j] = L_tmp;
+ }
+
+ /* Retrieve from isf_tmp[][] the ISF vectors saved prior to averaging */
+ for (k = 0; k < 2; k++)
+ {
+
+ if (indices[k] + 1 != 0)
+ {
+ for (i = 0; i < M; i++)
+ {
+ isf_old[indices[k] * M + i] = isf_tmp[k * M + i];
+ }
+ }
+ }
+
+ return;
+}
+
+
+/*----------------------------------------------------------------------------
+; FUNCTION CODE
+----------------------------------------------------------------------------*/
+
+void find_frame_indices(
+ int16 isf_old_tx[],
+ int16 indices[],
+ dtx_encState * st
+)
+{
+ int32 L_tmp, summin, summax, summax2nd;
+ int16 i, j, tmp;
+ int16 ptr;
+
+ /* Remove the effect of the oldest frame from the column */
+ /* sum sumD[0..DTX_HIST_SIZE-1]. sumD[DTX_HIST_SIZE] is */
+ /* not updated since it will be removed later. */
+
+ tmp = DTX_HIST_SIZE_MIN_ONE;
+ j = -1;
+ for (i = 0; i < DTX_HIST_SIZE_MIN_ONE; i++)
+ {
+ j += tmp;
+ st->sumD[i] = sub_int32(st->sumD[i], st->D[j]);
+ tmp--;
+ }
+
+ /* Shift the column sum sumD. The element sumD[DTX_HIST_SIZE-1] */
+ /* corresponding to the oldest frame is removed. The sum of */
+ /* the distances between the latest isf and other isfs, */
+ /* i.e. the element sumD[0], will be computed during this call. */
+ /* Hence this element is initialized to zero. */
+
+ for (i = DTX_HIST_SIZE_MIN_ONE; i > 0; i--)
+ {
+ st->sumD[i] = st->sumD[i - 1];
+ }
+ st->sumD[0] = 0;
+
+ /* Remove the oldest frame from the distance matrix. */
+ /* Note that the distance matrix is replaced by a one- */
+ /* dimensional array to save static memory. */
+
+ tmp = 0;
+ for (i = 27; i >= 12; i -= tmp)
+ {
+ tmp++;
+ for (j = tmp; j > 0; j--)
+ {
+ st->D[i - j + 1] = st->D[i - j - tmp];
+ }
+ }
+
+ /* Compute the first column of the distance matrix D */
+ /* (squared Euclidean distances from isf1[] to isf_old_tx[][]). */
+
+ ptr = st->hist_ptr;
+ for (i = 1; i < DTX_HIST_SIZE; i++)
+ {
+ /* Compute the distance between the latest isf and the other isfs. */
+ ptr--;
+
+ if (ptr < 0)
+ {
+ ptr = DTX_HIST_SIZE_MIN_ONE;
+ }
+ L_tmp = 0;
+ for (j = 0; j < M; j++)
+ {
+ tmp = sub_int16(isf_old_tx[st->hist_ptr * M + j], isf_old_tx[ptr * M + j]);
+ L_tmp = mac_16by16_to_int32(L_tmp, tmp, tmp);
+ }
+ st->D[i - 1] = L_tmp;
+
+ /* Update also the column sums. */
+ st->sumD[0] = add_int32(st->sumD[0], st->D[i - 1]);
+ st->sumD[i] = add_int32(st->sumD[i], st->D[i - 1]);
+ }
+
+ /* Find the minimum and maximum distances */
+ summax = st->sumD[0];
+ summin = st->sumD[0];
+ indices[0] = 0;
+ indices[2] = 0;
+ for (i = 1; i < DTX_HIST_SIZE; i++)
+ {
+
+ if (st->sumD[i] > summax)
+ {
+ indices[0] = i;
+ summax = st->sumD[i];
+ }
+
+ if (st->sumD[i] < summin)
+ {
+ indices[2] = i;
+ summin = st->sumD[i];
+ }
+ }
+
+ /* Find the second largest distance */
+ summax2nd = -2147483647L;
+ indices[1] = -1;
+ for (i = 0; i < DTX_HIST_SIZE; i++)
+ {
+
+ if ((st->sumD[i] > summax2nd) && (i != indices[0]))
+ {
+ indices[1] = i;
+ summax2nd = st->sumD[i];
+ }
+ }
+
+ for (i = 0; i < 3; i++)
+ {
+ indices[i] = sub_int16(st->hist_ptr, indices[i]);
+
+ if (indices[i] < 0)
+ {
+ indices[i] = add_int16(indices[i], DTX_HIST_SIZE);
+ }
+ }
+
+ /* If maximum distance/MED_THRESH is smaller than minimum distance */
+ /* then the median ISF vector replacement is not performed */
+ tmp = normalize_amr_wb(summax);
+ summax <<= tmp;
+ summin <<= tmp;
+ L_tmp = mul_16by16_to_int32(amr_wb_round(summax), INV_MED_THRESH);
+
+ if (L_tmp <= summin)
+ {
+ indices[0] = -1;
+ }
+ /* If second largest distance/MED_THRESH is smaller than */
+ /* minimum distance then the median ISF vector replacement is */
+ /* not performed */
+ summax2nd = shl_int32(summax2nd, tmp);
+ L_tmp = mul_16by16_to_int32(amr_wb_round(summax2nd), INV_MED_THRESH);
+
+ if (L_tmp <= summin)
+ {
+ indices[1] = -1;
+ }
+ return;
+}
+
+
+/*----------------------------------------------------------------------------
+; FUNCTION CODE
+----------------------------------------------------------------------------*/
+
+int16 dithering_control(dtx_encState * st)
+{
+ int16 i, tmp, mean, CN_dith, gain_diff;
+ int32 ISF_diff;
+
+ /* determine how stationary the spectrum of background noise is */
+ ISF_diff = 0;
+ for (i = 0; i < 8; i++)
+ {
+ ISF_diff = add_int32(ISF_diff, st->sumD[i]);
+ }
+ if ((ISF_diff >> 26) > 0)
+ {
+ CN_dith = 1;
+ }
+ else
+ {
+ CN_dith = 0;
+ }
+
+ /* determine how stationary the energy of background noise is */
+ mean = 0;
+ for (i = 0; i < DTX_HIST_SIZE; i++)
+ {
+ mean = add_int16(mean, st->log_en_hist[i]);
+ }
+ mean >>= 3;
+ gain_diff = 0;
+ for (i = 0; i < DTX_HIST_SIZE; i++)
+ {
+ tmp = sub_int16(st->log_en_hist[i], mean);
+ tmp = tmp - (tmp < 0);
+
+ gain_diff += tmp ^(tmp >> 15); /* tmp ^sign(tmp) */;
+ }
+ if (gain_diff > GAIN_THR)
+ {
+ CN_dith = 1;
+ }
+ return CN_dith;
+}
+
+
+/*----------------------------------------------------------------------------
+; FUNCTION CODE
+----------------------------------------------------------------------------*/
+
+void CN_dithering(
+ int16 isf[M],
+ int32 * L_log_en_int,
+ int16 * dither_seed
+)
+{
+ int16 temp, temp1, i, dither_fac, rand_dith;
+ int16 rand_dith2;
+
+ /* Insert comfort noise dithering for energy parameter */
+ rand_dith = noise_gen_amrwb(dither_seed) >> 1;
+ rand_dith2 = noise_gen_amrwb(dither_seed) >> 1;
+ rand_dith += rand_dith2;
+ *L_log_en_int = add_int32(*L_log_en_int, mul_16by16_to_int32(rand_dith, GAIN_FACTOR));
+
+ if (*L_log_en_int < 0)
+ {
+ *L_log_en_int = 0;
+ }
+ /* Insert comfort noise dithering for spectral parameters (ISF-vector) */
+ dither_fac = ISF_FACTOR_LOW;
+
+ rand_dith = noise_gen_amrwb(dither_seed) >> 1;
+ rand_dith2 = noise_gen_amrwb(dither_seed) >> 1;
+ rand_dith += rand_dith2;
+ temp = add_int16(isf[0], mult_int16_r(rand_dith, dither_fac));
+
+ /* Make sure that isf[0] will not get negative values */
+ if (temp < ISF_GAP)
+ {
+ isf[0] = ISF_GAP;
+ }
+ else
+ {
+ isf[0] = temp;
+ }
+
+ for (i = 1; i < M - 1; i++)
+ {
+ dither_fac = add_int16(dither_fac, ISF_FACTOR_STEP);
+
+ rand_dith = noise_gen_amrwb(dither_seed) >> 1;
+ rand_dith2 = noise_gen_amrwb(dither_seed) >> 1;
+ rand_dith += rand_dith2;
+ temp = add_int16(isf[i], mult_int16_r(rand_dith, dither_fac));
+ temp1 = sub_int16(temp, isf[i - 1]);
+
+ /* Make sure that isf spacing remains at least ISF_DITH_GAP Hz */
+ if (temp1 < ISF_DITH_GAP)
+ {
+ isf[i] = isf[i - 1] + ISF_DITH_GAP;
+ }
+ else
+ {
+ isf[i] = temp;
+ }
+ }
+
+ /* Make sure that isf[M-2] will not get values above 16384 */
+ if (isf[M - 2] > 16384)
+ {
+ isf[M - 2] = 16384;
+ }
+ return;
+}