void WebRtcAecm_CalcLinearEnergiesNeon(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echo_est, uint32_t* far_energy, uint32_t* echo_energy_adapt, uint32_t* echo_energy_stored) { int16_t* start_stored_p = aecm->channelStored; int16_t* start_adapt_p = aecm->channelAdapt16; int32_t* echo_est_p = echo_est; const int16_t* end_stored_p = aecm->channelStored + PART_LEN; const uint16_t* far_spectrum_p = far_spectrum; int16x8_t store_v, adapt_v; uint16x8_t spectrum_v; uint32x4_t echo_est_v_low, echo_est_v_high; uint32x4_t far_energy_v, echo_stored_v, echo_adapt_v; far_energy_v = vdupq_n_u32(0); echo_adapt_v = vdupq_n_u32(0); echo_stored_v = vdupq_n_u32(0); // Get energy for the delayed far end signal and estimated // echo using both stored and adapted channels. // The C code: // for (i = 0; i < PART_LEN1; i++) { // echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], // far_spectrum[i]); // (*far_energy) += (uint32_t)(far_spectrum[i]); // *echo_energy_adapt += aecm->channelAdapt16[i] * far_spectrum[i]; // (*echo_energy_stored) += (uint32_t)echo_est[i]; // } while (start_stored_p < end_stored_p) { spectrum_v = vld1q_u16(far_spectrum_p); adapt_v = vld1q_s16(start_adapt_p); store_v = vld1q_s16(start_stored_p); far_energy_v = vaddw_u16(far_energy_v, vget_low_u16(spectrum_v)); far_energy_v = vaddw_u16(far_energy_v, vget_high_u16(spectrum_v)); echo_est_v_low = vmull_u16(vreinterpret_u16_s16(vget_low_s16(store_v)), vget_low_u16(spectrum_v)); echo_est_v_high = vmull_u16(vreinterpret_u16_s16(vget_high_s16(store_v)), vget_high_u16(spectrum_v)); vst1q_s32(echo_est_p, vreinterpretq_s32_u32(echo_est_v_low)); vst1q_s32(echo_est_p + 4, vreinterpretq_s32_u32(echo_est_v_high)); echo_stored_v = vaddq_u32(echo_est_v_low, echo_stored_v); echo_stored_v = vaddq_u32(echo_est_v_high, echo_stored_v); echo_adapt_v = vmlal_u16(echo_adapt_v, vreinterpret_u16_s16(vget_low_s16(adapt_v)), vget_low_u16(spectrum_v)); echo_adapt_v = vmlal_u16(echo_adapt_v, vreinterpret_u16_s16(vget_high_s16(adapt_v)), vget_high_u16(spectrum_v)); start_stored_p += 8; start_adapt_p += 8; far_spectrum_p += 8; echo_est_p += 8; } AddLanes(far_energy, far_energy_v); AddLanes(echo_energy_stored, echo_stored_v); AddLanes(echo_energy_adapt, echo_adapt_v); echo_est[PART_LEN] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[PART_LEN], far_spectrum[PART_LEN]); *echo_energy_stored += (uint32_t)echo_est[PART_LEN]; *far_energy += (uint32_t)far_spectrum[PART_LEN]; *echo_energy_adapt += aecm->channelAdapt16[PART_LEN] * far_spectrum[PART_LEN]; }
int WebRtcNetEQ_UpdateIatStatistics(AutomodeInst_t *inst, int maxBufLen, uint16_t seqNumber, uint32_t timeStamp, int32_t fsHz, int mdCodec, int streamingMode) { uint32_t timeIat; /* inter-arrival time */ int i; int32_t tempsum = 0; /* temp summation */ int32_t tempvar; /* temporary variable */ int retval = 0; /* return value */ int16_t packetLenSamp; /* packet speech length in samples */ /****************/ /* Sanity check */ /****************/ if (maxBufLen <= 1 || fsHz <= 0) { /* maxBufLen must be at least 2 and fsHz must both be strictly positive */ return -1; } /****************************/ /* Update packet statistics */ /****************************/ /* Try calculating packet length from current and previous timestamps */ if (!WebRtcNetEQ_IsNewerTimestamp(timeStamp, inst->lastTimeStamp) || !WebRtcNetEQ_IsNewerSequenceNumber(seqNumber, inst->lastSeqNo)) { /* Wrong timestamp or sequence order; revert to backup plan */ packetLenSamp = inst->packetSpeechLenSamp; /* use stored value */ } else { /* calculate timestamps per packet */ packetLenSamp = (int16_t) WebRtcSpl_DivU32U16(timeStamp - inst->lastTimeStamp, seqNumber - inst->lastSeqNo); } /* Check that the packet size is positive; if not, the statistics cannot be updated. */ if (inst->firstPacketReceived && packetLenSamp > 0) { /* packet size ok */ /* calculate inter-arrival time in integer packets (rounding down) */ timeIat = WebRtcSpl_DivW32W16(inst->packetIatCountSamp, packetLenSamp); /* Special operations for streaming mode */ if (streamingMode != 0) { /* * Calculate IAT in Q8, including fractions of a packet (i.e., more accurate * than timeIat). */ int16_t timeIatQ8 = (int16_t) WebRtcSpl_DivW32W16( WEBRTC_SPL_LSHIFT_W32(inst->packetIatCountSamp, 8), packetLenSamp); /* * Calculate cumulative sum iat with sequence number compensation (ideal arrival * times makes this sum zero). */ inst->cSumIatQ8 += (timeIatQ8 - WEBRTC_SPL_LSHIFT_W32(seqNumber - inst->lastSeqNo, 8)); /* subtract drift term */ inst->cSumIatQ8 -= CSUM_IAT_DRIFT; /* ensure not negative */ inst->cSumIatQ8 = WEBRTC_SPL_MAX(inst->cSumIatQ8, 0); /* remember max */ if (inst->cSumIatQ8 > inst->maxCSumIatQ8) { inst->maxCSumIatQ8 = inst->cSumIatQ8; inst->maxCSumUpdateTimer = 0; } /* too long since the last maximum was observed; decrease max value */ if (inst->maxCSumUpdateTimer > (uint32_t) WEBRTC_SPL_MUL_32_16(fsHz, MAX_STREAMING_PEAK_PERIOD)) { inst->maxCSumIatQ8 -= 4; /* remove 1000*4/256 = 15.6 ms/s */ } } /* end of streaming mode */ /* check for discontinuous packet sequence and re-ordering */ if (WebRtcNetEQ_IsNewerSequenceNumber(seqNumber, inst->lastSeqNo + 1)) { /* Compensate for gap in the sequence numbers. * Reduce IAT with expected extra time due to lost packets, but ensure that * the IAT is not negative. */ timeIat -= WEBRTC_SPL_MIN(timeIat, (uint16_t) (seqNumber - (uint16_t) (inst->lastSeqNo + 1))); } else if (!WebRtcNetEQ_IsNewerSequenceNumber(seqNumber, inst->lastSeqNo)) { /* compensate for re-ordering */ timeIat += (uint16_t) (inst->lastSeqNo + 1 - seqNumber); } /* saturate IAT at maximum value */ timeIat = WEBRTC_SPL_MIN( timeIat, MAX_IAT ); /* update iatProb = forgetting_factor * iatProb for all elements */ for (i = 0; i <= MAX_IAT; i++) { int32_t tempHi, tempLo; /* Temporary variables */ /* * Multiply iatProbFact (Q15) with iatProb (Q30) and right-shift 15 steps * to come back to Q30. The operation is done in two steps: */ /* * 1) Multiply the high 16 bits (15 bits + sign) of iatProb. Shift iatProb * 16 steps right to get the high 16 bits in a int16_t prior to * multiplication, and left-shift with 1 afterwards to come back to * Q30 = (Q15 * (Q30>>16)) << 1. */ tempHi = WEBRTC_SPL_MUL_16_16(inst->iatProbFact, (int16_t) WEBRTC_SPL_RSHIFT_W32(inst->iatProb[i], 16)); tempHi = WEBRTC_SPL_LSHIFT_W32(tempHi, 1); /* left-shift 1 step */ /* * 2) Isolate and multiply the low 16 bits of iatProb. Right-shift 15 steps * afterwards to come back to Q30 = (Q15 * Q30) >> 15. */ tempLo = inst->iatProb[i] & 0x0000FFFF; /* sift out the 16 low bits */ tempLo = WEBRTC_SPL_MUL_16_U16(inst->iatProbFact, (uint16_t) tempLo); tempLo = WEBRTC_SPL_RSHIFT_W32(tempLo, 15); /* Finally, add the high and low parts */ inst->iatProb[i] = tempHi + tempLo; /* Sum all vector elements while we are at it... */ tempsum += inst->iatProb[i]; } /* * Increase the probability for the currently observed inter-arrival time * with 1 - iatProbFact. The factor is in Q15, iatProb in Q30; * hence, left-shift 15 steps to obtain result in Q30. */ inst->iatProb[timeIat] += (32768 - inst->iatProbFact) << 15; tempsum += (32768 - inst->iatProbFact) << 15; /* add to vector sum */ /* * Update iatProbFact (changes only during the first seconds after reset) * The factor converges to IAT_PROB_FACT. */ inst->iatProbFact += (IAT_PROB_FACT - inst->iatProbFact + 3) >> 2; /* iatProb should sum up to 1 (in Q30). */ tempsum -= 1 << 30; /* should be zero */ /* Check if it does, correct if it doesn't. */ if (tempsum > 0) { /* tempsum too large => decrease a few values in the beginning */ i = 0; while (i <= MAX_IAT && tempsum > 0) { /* Remove iatProb[i] / 16 from iatProb, but not more than tempsum */ tempvar = WEBRTC_SPL_MIN(tempsum, inst->iatProb[i] >> 4); inst->iatProb[i++] -= tempvar; tempsum -= tempvar; } }