/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * Implementation of the peak detection used for finding correlation peaks. */ #include "dsp_helpfunctions.h" #include "signal_processing_library.h" /* Table of constants used in parabolic fit function WebRtcNetEQ_PrblFit */ const WebRtc_Word16 WebRtcNetEQ_kPrblCf[17][3] = { { 120, 32, 64 }, { 140, 44, 75 }, { 150, 50, 80 }, { 160, 57, 85 }, { 180, 72, 96 }, { 200, 89, 107 }, { 210, 98, 112 }, { 220, 108, 117 }, { 240, 128, 128 }, { 260, 150, 139 }, { 270, 162, 144 }, { 280, 174, 149 }, { 300, 200, 160 }, { 320, 228, 171 }, { 330, 242, 176 }, { 340, 257, 181 }, { 360, 288, 192 } }; WebRtc_Word16 WebRtcNetEQ_PeakDetection(WebRtc_Word16 *pw16_data, WebRtc_Word16 w16_dataLen, WebRtc_Word16 w16_nmbPeaks, WebRtc_Word16 fs_mult, WebRtc_Word16 *pw16_winIndex, WebRtc_Word16 *pw16_winValue) { /* Local variables */ int i; WebRtc_Word16 w16_tmp; WebRtc_Word16 w16_tmp2; WebRtc_Word16 indMin = 0; WebRtc_Word16 indMax = 0; /* Peak detection */ for (i = 0; i <= (w16_nmbPeaks - 1); i++) { if (w16_nmbPeaks == 1) { /* * Single peak * The parabola fit assumes that an extra point is available; worst case it gets * a zero on the high end of the signal. */ w16_dataLen++; } pw16_winIndex[i] = WebRtcSpl_MaxIndexW16(pw16_data, (WebRtc_Word16) (w16_dataLen - 1)); if (i != w16_nmbPeaks - 1) { w16_tmp = pw16_winIndex[i] - 2; /* *fs_mult; */ indMin = WEBRTC_SPL_MAX(0, w16_tmp); w16_tmp = pw16_winIndex[i] + 2; /* *fs_mult; */ w16_tmp2 = w16_dataLen - 1; indMax = WEBRTC_SPL_MIN(w16_tmp2, w16_tmp); } if ((pw16_winIndex[i] != 0) && (pw16_winIndex[i] != (w16_dataLen - 2))) { /* Parabola fit*/ WebRtcNetEQ_PrblFit(&(pw16_data[pw16_winIndex[i] - 1]), &(pw16_winIndex[i]), &(pw16_winValue[i]), fs_mult); } else { if (pw16_winIndex[i] == (w16_dataLen - 2)) { if (pw16_data[pw16_winIndex[i]] > pw16_data[pw16_winIndex[i] + 1]) { WebRtcNetEQ_PrblFit(&(pw16_data[pw16_winIndex[i] - 1]), &(pw16_winIndex[i]), &(pw16_winValue[i]), fs_mult); } else if (pw16_data[pw16_winIndex[i]] <= pw16_data[pw16_winIndex[i] + 1]) { pw16_winValue[i] = (pw16_data[pw16_winIndex[i]] + pw16_data[pw16_winIndex[i] + 1]) >> 1; /* lin approx */ pw16_winIndex[i] = (pw16_winIndex[i] * 2 + 1) * fs_mult; } } else { pw16_winValue[i] = pw16_data[pw16_winIndex[i]]; pw16_winIndex[i] = pw16_winIndex[i] * 2 * fs_mult; } } if (i != w16_nmbPeaks - 1) { WebRtcSpl_MemSetW16(&(pw16_data[indMin]), 0, (indMax - indMin + 1)); /* for (j=indMin; j<=indMax; j++) pw16_data[j] = 0; */ } } return 0; } WebRtc_Word16 WebRtcNetEQ_PrblFit(WebRtc_Word16 *pw16_3pts, WebRtc_Word16 *pw16_Ind, WebRtc_Word16 *pw16_outVal, WebRtc_Word16 fs_mult) { /* Variables */ WebRtc_Word32 Num, Den; WebRtc_Word32 temp; WebRtc_Word16 flag, stp, strt, lmt; WebRtc_UWord16 PFind[13]; if (fs_mult == 1) { PFind[0] = 0; PFind[1] = 8; PFind[2] = 16; } else if (fs_mult == 2) { PFind[0] = 0; PFind[1] = 4; PFind[2] = 8; PFind[3] = 12; PFind[4] = 16; } else if (fs_mult == 4) { PFind[0] = 0; PFind[1] = 2; PFind[2] = 4; PFind[3] = 6; PFind[4] = 8; PFind[5] = 10; PFind[6] = 12; PFind[7] = 14; PFind[8] = 16; } else { PFind[0] = 0; PFind[1] = 1; PFind[2] = 3; PFind[3] = 4; PFind[4] = 5; PFind[5] = 7; PFind[6] = 8; PFind[7] = 9; PFind[8] = 11; PFind[9] = 12; PFind[10] = 13; PFind[11] = 15; PFind[12] = 16; } /* Num = -3*pw16_3pts[0] + 4*pw16_3pts[1] - pw16_3pts[2]; */ /* Den = pw16_3pts[0] - 2*pw16_3pts[1] + pw16_3pts[2]; */ Num = WEBRTC_SPL_MUL_16_16(pw16_3pts[0],-3) + WEBRTC_SPL_MUL_16_16(pw16_3pts[1],4) - pw16_3pts[2]; Den = pw16_3pts[0] + WEBRTC_SPL_MUL_16_16(pw16_3pts[1],-2) + pw16_3pts[2]; temp = (WebRtc_Word32) WEBRTC_SPL_MUL(Num, (WebRtc_Word32)120); /* need 32_16 really */ flag = 1; stp = WebRtcNetEQ_kPrblCf[PFind[fs_mult]][0] - WebRtcNetEQ_kPrblCf[PFind[fs_mult - 1]][0]; strt = (WebRtcNetEQ_kPrblCf[PFind[fs_mult]][0] + WebRtcNetEQ_kPrblCf[PFind[fs_mult - 1]][0]) >> 1; if (temp < (WebRtc_Word32) WEBRTC_SPL_MUL(-Den,(WebRtc_Word32)strt)) { lmt = strt - stp; while (flag) { if ((flag == fs_mult) || (temp > (WebRtc_Word32) WEBRTC_SPL_MUL(-Den,(WebRtc_Word32)lmt))) { *pw16_outVal = (WebRtc_Word16) (((WebRtc_Word32) ((WebRtc_Word32) WEBRTC_SPL_MUL(Den,(WebRtc_Word32)WebRtcNetEQ_kPrblCf[PFind[fs_mult-flag]][1]) + (WebRtc_Word32) WEBRTC_SPL_MUL(Num,(WebRtc_Word32)WebRtcNetEQ_kPrblCf[PFind[fs_mult-flag]][2]) + WEBRTC_SPL_MUL_16_16(pw16_3pts[0],256))) >> 8); *pw16_Ind = (*pw16_Ind) * (fs_mult << 1) - flag; flag = 0; } else { flag++; lmt -= stp; } } } else if (temp > (WebRtc_Word32) WEBRTC_SPL_MUL(-Den,(WebRtc_Word32)(strt+stp))) { lmt = strt + (stp << 1); while (flag) { if ((flag == fs_mult) || (temp < (WebRtc_Word32) WEBRTC_SPL_MUL(-Den,(WebRtc_Word32)lmt))) { WebRtc_Word32 temp_term_1, temp_term_2, temp_term_3; temp_term_1 = WEBRTC_SPL_MUL(Den, (WebRtc_Word32) WebRtcNetEQ_kPrblCf[PFind[fs_mult+flag]][1]); temp_term_2 = WEBRTC_SPL_MUL(Num, (WebRtc_Word32) WebRtcNetEQ_kPrblCf[PFind[fs_mult+flag]][2]); temp_term_3 = WEBRTC_SPL_MUL_16_16(pw16_3pts[0],256); *pw16_outVal = (WebRtc_Word16) ((temp_term_1 + temp_term_2 + temp_term_3) >> 8); *pw16_Ind = (*pw16_Ind) * (fs_mult << 1) + flag; flag = 0; } else { flag++; lmt += stp; } } } else { *pw16_outVal = pw16_3pts[1]; *pw16_Ind = (*pw16_Ind) * 2 * fs_mult; } return 0; }