| /* |
| * Copyright (c) 2012 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. |
| */ |
| |
| /* |
| * filterbanks.c |
| * |
| * This file contains function |
| * WebRtcIsacfix_SplitAndFilter, and WebRtcIsacfix_FilterAndCombine |
| * which implement filterbanks that produce decimated lowpass and |
| * highpass versions of a signal, and performs reconstruction. |
| * |
| */ |
| |
| #include "filterbank_internal.h" |
| |
| #include "codec.h" |
| #include "filterbank_tables.h" |
| #include "settings.h" |
| #include "webrtc/rtc_base/checks.h" |
| |
| // Declare a function pointer. |
| AllpassFilter2FixDec16 WebRtcIsacfix_AllpassFilter2FixDec16; |
| |
| void WebRtcIsacfix_AllpassFilter2FixDec16C( |
| int16_t *data_ch1, // Input and output in channel 1, in Q0 |
| int16_t *data_ch2, // Input and output in channel 2, in Q0 |
| const int16_t *factor_ch1, // Scaling factor for channel 1, in Q15 |
| const int16_t *factor_ch2, // Scaling factor for channel 2, in Q15 |
| const int length, // Length of the data buffers |
| int32_t *filter_state_ch1, // Filter state for channel 1, in Q16 |
| int32_t *filter_state_ch2) { // Filter state for channel 2, in Q16 |
| int n = 0; |
| int32_t state0_ch1 = filter_state_ch1[0], state1_ch1 = filter_state_ch1[1]; |
| int32_t state0_ch2 = filter_state_ch2[0], state1_ch2 = filter_state_ch2[1]; |
| int16_t in_out = 0; |
| int32_t a = 0, b = 0; |
| |
| // Assembly file assumption. |
| RTC_DCHECK_EQ(0, length % 2); |
| |
| for (n = 0; n < length; n++) { |
| // Process channel 1: |
| in_out = data_ch1[n]; |
| a = factor_ch1[0] * in_out; // Q15 * Q0 = Q15 |
| a *= 1 << 1; // Q15 -> Q16 |
| b = WebRtcSpl_AddSatW32(a, state0_ch1); |
| a = -factor_ch1[0] * (int16_t)(b >> 16); // Q15 |
| state0_ch1 = |
| WebRtcSpl_AddSatW32(a * (1 << 1), (int32_t)in_out * (1 << 16)); // Q16 |
| in_out = (int16_t) (b >> 16); // Save as Q0 |
| |
| a = factor_ch1[1] * in_out; // Q15 * Q0 = Q15 |
| a *= 1 << 1; // Q15 -> Q16 |
| b = WebRtcSpl_AddSatW32(a, state1_ch1); // Q16 |
| a = -factor_ch1[1] * (int16_t)(b >> 16); // Q15 |
| state1_ch1 = |
| WebRtcSpl_AddSatW32(a * (1 << 1), (int32_t)in_out * (1 << 16)); // Q16 |
| data_ch1[n] = (int16_t) (b >> 16); // Save as Q0 |
| |
| // Process channel 2: |
| in_out = data_ch2[n]; |
| a = factor_ch2[0] * in_out; // Q15 * Q0 = Q15 |
| a *= 1 << 1; // Q15 -> Q16 |
| b = WebRtcSpl_AddSatW32(a, state0_ch2); // Q16 |
| a = -factor_ch2[0] * (int16_t)(b >> 16); // Q15 |
| state0_ch2 = |
| WebRtcSpl_AddSatW32(a * (1 << 1), (int32_t)in_out * (1 << 16)); // Q16 |
| in_out = (int16_t) (b >> 16); // Save as Q0 |
| |
| a = factor_ch2[1] * in_out; // Q15 * Q0 = Q15 |
| a *= (1 << 1); // Q15 -> Q16 |
| b = WebRtcSpl_AddSatW32(a, state1_ch2); // Q16 |
| a = -factor_ch2[1] * (int16_t)(b >> 16); // Q15 |
| state1_ch2 = |
| WebRtcSpl_AddSatW32(a * (1 << 1), (int32_t)in_out * (1 << 16)); // Q16 |
| data_ch2[n] = (int16_t) (b >> 16); // Save as Q0 |
| } |
| |
| filter_state_ch1[0] = state0_ch1; |
| filter_state_ch1[1] = state1_ch1; |
| filter_state_ch2[0] = state0_ch2; |
| filter_state_ch2[1] = state1_ch2; |
| } |
| |
| // Declare a function pointer. |
| HighpassFilterFixDec32 WebRtcIsacfix_HighpassFilterFixDec32; |
| |
| void WebRtcIsacfix_HighpassFilterFixDec32C(int16_t *io, |
| int16_t len, |
| const int16_t *coefficient, |
| int32_t *state) |
| { |
| int k; |
| int32_t a1 = 0, b1 = 0, c = 0, in = 0; |
| int32_t a2 = 0, b2 = 0; |
| int32_t state0 = state[0]; |
| int32_t state1 = state[1]; |
| |
| for (k=0; k<len; k++) { |
| in = (int32_t)io[k]; |
| |
| #ifdef WEBRTC_ARCH_ARM_V7 |
| { |
| register int tmp_coeff0; |
| register int tmp_coeff1; |
| __asm __volatile( |
| "ldr %[tmp_coeff0], [%[coeff]]\n\t" |
| "ldr %[tmp_coeff1], [%[coeff], #4]\n\t" |
| "smmulr %[a2], %[tmp_coeff0], %[state0]\n\t" |
| "smmulr %[b2], %[tmp_coeff1], %[state1]\n\t" |
| "ldr %[tmp_coeff0], [%[coeff], #8]\n\t" |
| "ldr %[tmp_coeff1], [%[coeff], #12]\n\t" |
| "smmulr %[a1], %[tmp_coeff0], %[state0]\n\t" |
| "smmulr %[b1], %[tmp_coeff1], %[state1]\n\t" |
| :[a2]"=&r"(a2), |
| [b2]"=&r"(b2), |
| [a1]"=&r"(a1), |
| [b1]"=r"(b1), |
| [tmp_coeff0]"=&r"(tmp_coeff0), |
| [tmp_coeff1]"=&r"(tmp_coeff1) |
| :[coeff]"r"(coefficient), |
| [state0]"r"(state0), |
| [state1]"r"(state1) |
| ); |
| } |
| #else |
| /* Q35 * Q4 = Q39 ; shift 32 bit => Q7 */ |
| a1 = WEBRTC_SPL_MUL_16_32_RSFT16(coefficient[5], state0) + |
| (WEBRTC_SPL_MUL_16_32_RSFT16(coefficient[4], state0) >> 16); |
| b1 = WEBRTC_SPL_MUL_16_32_RSFT16(coefficient[7], state1) + |
| (WEBRTC_SPL_MUL_16_32_RSFT16(coefficient[6], state1) >> 16); |
| |
| /* Q30 * Q4 = Q34 ; shift 32 bit => Q2 */ |
| a2 = WEBRTC_SPL_MUL_16_32_RSFT16(coefficient[1], state0) + |
| (WEBRTC_SPL_MUL_16_32_RSFT16(coefficient[0], state0) >> 16); |
| b2 = WEBRTC_SPL_MUL_16_32_RSFT16(coefficient[3], state1) + |
| (WEBRTC_SPL_MUL_16_32_RSFT16(coefficient[2], state1) >> 16); |
| #endif |
| |
| c = in + ((a1 + b1) >> 7); // Q0. |
| io[k] = (int16_t)WebRtcSpl_SatW32ToW16(c); // Write output as Q0. |
| |
| c = in * (1 << 2) - a2 - b2; // In Q2. |
| c = (int32_t)WEBRTC_SPL_SAT(536870911, c, -536870912); |
| |
| state1 = state0; |
| state0 = c * (1 << 2); // Write state as Q4 |
| } |
| state[0] = state0; |
| state[1] = state1; |
| } |
| |
| |
| void WebRtcIsacfix_SplitAndFilter1(int16_t *pin, |
| int16_t *LP16, |
| int16_t *HP16, |
| PreFiltBankstr *prefiltdata) |
| { |
| /* Function WebRtcIsacfix_SplitAndFilter */ |
| /* This function creates low-pass and high-pass decimated versions of part of |
| the input signal, and part of the signal in the input 'lookahead buffer'. */ |
| |
| int k; |
| |
| int16_t tempin_ch1[FRAMESAMPLES/2 + QLOOKAHEAD]; |
| int16_t tempin_ch2[FRAMESAMPLES/2 + QLOOKAHEAD]; |
| int32_t tmpState_ch1[2 * (QORDER-1)]; /* 4 */ |
| int32_t tmpState_ch2[2 * (QORDER-1)]; /* 4 */ |
| |
| /* High pass filter */ |
| WebRtcIsacfix_HighpassFilterFixDec32(pin, FRAMESAMPLES, WebRtcIsacfix_kHpStCoeffInQ30, prefiltdata->HPstates_fix); |
| |
| |
| /* First Channel */ |
| for (k=0;k<FRAMESAMPLES/2;k++) { |
| tempin_ch1[QLOOKAHEAD + k] = pin[1 + 2 * k]; |
| } |
| for (k=0;k<QLOOKAHEAD;k++) { |
| tempin_ch1[k]=prefiltdata->INLABUF1_fix[k]; |
| prefiltdata->INLABUF1_fix[k] = pin[FRAMESAMPLES + 1 - 2 * (QLOOKAHEAD - k)]; |
| } |
| |
| /* Second Channel. This is exactly like the first channel, except that the |
| even samples are now filtered instead (lower channel). */ |
| for (k=0;k<FRAMESAMPLES/2;k++) { |
| tempin_ch2[QLOOKAHEAD + k] = pin[2 * k]; |
| } |
| for (k=0;k<QLOOKAHEAD;k++) { |
| tempin_ch2[k]=prefiltdata->INLABUF2_fix[k]; |
| prefiltdata->INLABUF2_fix[k] = pin[FRAMESAMPLES - 2 * (QLOOKAHEAD - k)]; |
| } |
| |
| |
| /*obtain polyphase components by forward all-pass filtering through each channel */ |
| /* The all pass filtering automatically updates the filter states which are exported in the |
| prefiltdata structure */ |
| WebRtcIsacfix_AllpassFilter2FixDec16(tempin_ch1, |
| tempin_ch2, |
| WebRtcIsacfix_kUpperApFactorsQ15, |
| WebRtcIsacfix_kLowerApFactorsQ15, |
| FRAMESAMPLES/2, |
| prefiltdata->INSTAT1_fix, |
| prefiltdata->INSTAT2_fix); |
| |
| for (k = 0; k < 2 * (QORDER - 1); k++) { |
| tmpState_ch1[k] = prefiltdata->INSTAT1_fix[k]; |
| tmpState_ch2[k] = prefiltdata->INSTAT2_fix[k]; |
| } |
| WebRtcIsacfix_AllpassFilter2FixDec16(tempin_ch1 + FRAMESAMPLES/2, |
| tempin_ch2 + FRAMESAMPLES/2, |
| WebRtcIsacfix_kUpperApFactorsQ15, |
| WebRtcIsacfix_kLowerApFactorsQ15, |
| QLOOKAHEAD, |
| tmpState_ch1, |
| tmpState_ch2); |
| |
| /* Now Construct low-pass and high-pass signals as combinations of polyphase components */ |
| for (k=0; k<FRAMESAMPLES/2 + QLOOKAHEAD; k++) { |
| int32_t tmp1, tmp2, tmp3; |
| tmp1 = (int32_t)tempin_ch1[k]; // Q0 -> Q0 |
| tmp2 = (int32_t)tempin_ch2[k]; // Q0 -> Q0 |
| tmp3 = (tmp1 + tmp2) >> 1; /* Low pass signal. */ |
| LP16[k] = (int16_t)WebRtcSpl_SatW32ToW16(tmp3); /*low pass */ |
| tmp3 = (tmp1 - tmp2) >> 1; /* High pass signal. */ |
| HP16[k] = (int16_t)WebRtcSpl_SatW32ToW16(tmp3); /*high pass */ |
| } |
| |
| }/*end of WebRtcIsacfix_SplitAndFilter */ |
| |
| |
| #ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED |
| |
| /* Without lookahead */ |
| void WebRtcIsacfix_SplitAndFilter2(int16_t *pin, |
| int16_t *LP16, |
| int16_t *HP16, |
| PreFiltBankstr *prefiltdata) |
| { |
| /* Function WebRtcIsacfix_SplitAndFilter2 */ |
| /* This function creates low-pass and high-pass decimated versions of part of |
| the input signal. */ |
| |
| int k; |
| |
| int16_t tempin_ch1[FRAMESAMPLES/2]; |
| int16_t tempin_ch2[FRAMESAMPLES/2]; |
| |
| |
| /* High pass filter */ |
| WebRtcIsacfix_HighpassFilterFixDec32(pin, FRAMESAMPLES, WebRtcIsacfix_kHpStCoeffInQ30, prefiltdata->HPstates_fix); |
| |
| |
| /* First Channel */ |
| for (k=0;k<FRAMESAMPLES/2;k++) { |
| tempin_ch1[k] = pin[1 + 2 * k]; |
| } |
| |
| /* Second Channel. This is exactly like the first channel, except that the |
| even samples are now filtered instead (lower channel). */ |
| for (k=0;k<FRAMESAMPLES/2;k++) { |
| tempin_ch2[k] = pin[2 * k]; |
| } |
| |
| |
| /*obtain polyphase components by forward all-pass filtering through each channel */ |
| /* The all pass filtering automatically updates the filter states which are exported in the |
| prefiltdata structure */ |
| WebRtcIsacfix_AllpassFilter2FixDec16(tempin_ch1, |
| tempin_ch2, |
| WebRtcIsacfix_kUpperApFactorsQ15, |
| WebRtcIsacfix_kLowerApFactorsQ15, |
| FRAMESAMPLES/2, |
| prefiltdata->INSTAT1_fix, |
| prefiltdata->INSTAT2_fix); |
| |
| /* Now Construct low-pass and high-pass signals as combinations of polyphase components */ |
| for (k=0; k<FRAMESAMPLES/2; k++) { |
| int32_t tmp1, tmp2, tmp3; |
| tmp1 = (int32_t)tempin_ch1[k]; // Q0 -> Q0 |
| tmp2 = (int32_t)tempin_ch2[k]; // Q0 -> Q0 |
| tmp3 = (tmp1 + tmp2) >> 1; /* Low pass signal. */ |
| LP16[k] = (int16_t)WebRtcSpl_SatW32ToW16(tmp3); /*low pass */ |
| tmp3 = (tmp1 - tmp2) >> 1; /* High pass signal. */ |
| HP16[k] = (int16_t)WebRtcSpl_SatW32ToW16(tmp3); /*high pass */ |
| } |
| |
| }/*end of WebRtcIsacfix_SplitAndFilter */ |
| |
| #endif |
| |
| |
| |
| ////////////////////////////////////////////////////////// |
| ////////// Combining |
| /* Function WebRtcIsacfix_FilterAndCombine */ |
| /* This is a decoder function that takes the decimated |
| length FRAMESAMPLES/2 input low-pass and |
| high-pass signals and creates a reconstructed fullband |
| output signal of length FRAMESAMPLES. WebRtcIsacfix_FilterAndCombine |
| is the sibling function of WebRtcIsacfix_SplitAndFilter */ |
| /* INPUTS: |
| inLP: a length FRAMESAMPLES/2 array of input low-pass |
| samples. |
| inHP: a length FRAMESAMPLES/2 array of input high-pass |
| samples. |
| postfiltdata: input data structure containing the filterbank |
| states from the previous decoding iteration. |
| OUTPUTS: |
| Out: a length FRAMESAMPLES array of output reconstructed |
| samples (fullband) based on the input low-pass and |
| high-pass signals. |
| postfiltdata: the input data structure containing the filterbank |
| states is updated for the next decoding iteration */ |
| void WebRtcIsacfix_FilterAndCombine1(int16_t *tempin_ch1, |
| int16_t *tempin_ch2, |
| int16_t *out16, |
| PostFiltBankstr *postfiltdata) |
| { |
| int k; |
| int16_t in[FRAMESAMPLES]; |
| |
| /* all-pass filter the new upper and lower channel signal. |
| For upper channel, use the all-pass filter factors that were used as a |
| lower channel at the encoding side. So at the decoder, the corresponding |
| all-pass filter factors for each channel are swapped. |
| For lower channel signal, since all-pass filter factors at the decoder are |
| swapped from the ones at the encoder, the 'upper' channel all-pass filter |
| factors (kUpperApFactors) are used to filter this new lower channel signal. |
| */ |
| WebRtcIsacfix_AllpassFilter2FixDec16(tempin_ch1, |
| tempin_ch2, |
| WebRtcIsacfix_kLowerApFactorsQ15, |
| WebRtcIsacfix_kUpperApFactorsQ15, |
| FRAMESAMPLES/2, |
| postfiltdata->STATE_0_UPPER_fix, |
| postfiltdata->STATE_0_LOWER_fix); |
| |
| /* Merge outputs to form the full length output signal.*/ |
| for (k=0;k<FRAMESAMPLES/2;k++) { |
| in[2 * k] = tempin_ch2[k]; |
| in[2 * k + 1] = tempin_ch1[k]; |
| } |
| |
| /* High pass filter */ |
| WebRtcIsacfix_HighpassFilterFixDec32(in, FRAMESAMPLES, WebRtcIsacfix_kHPStCoeffOut1Q30, postfiltdata->HPstates1_fix); |
| WebRtcIsacfix_HighpassFilterFixDec32(in, FRAMESAMPLES, WebRtcIsacfix_kHPStCoeffOut2Q30, postfiltdata->HPstates2_fix); |
| |
| for (k=0;k<FRAMESAMPLES;k++) { |
| out16[k] = in[k]; |
| } |
| } |
| |
| |
| #ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED |
| /* Function WebRtcIsacfix_FilterAndCombine */ |
| /* This is a decoder function that takes the decimated |
| length len/2 input low-pass and |
| high-pass signals and creates a reconstructed fullband |
| output signal of length len. WebRtcIsacfix_FilterAndCombine |
| is the sibling function of WebRtcIsacfix_SplitAndFilter */ |
| /* INPUTS: |
| inLP: a length len/2 array of input low-pass |
| samples. |
| inHP: a length len/2 array of input high-pass |
| samples. |
| postfiltdata: input data structure containing the filterbank |
| states from the previous decoding iteration. |
| OUTPUTS: |
| Out: a length len array of output reconstructed |
| samples (fullband) based on the input low-pass and |
| high-pass signals. |
| postfiltdata: the input data structure containing the filterbank |
| states is updated for the next decoding iteration */ |
| void WebRtcIsacfix_FilterAndCombine2(int16_t *tempin_ch1, |
| int16_t *tempin_ch2, |
| int16_t *out16, |
| PostFiltBankstr *postfiltdata, |
| int16_t len) |
| { |
| int k; |
| int16_t in[FRAMESAMPLES]; |
| |
| /* all-pass filter the new upper and lower channel signal. |
| For upper channel, use the all-pass filter factors that were used as a |
| lower channel at the encoding side. So at the decoder, the corresponding |
| all-pass filter factors for each channel are swapped. |
| For lower channel signal, since all-pass filter factors at the decoder are |
| swapped from the ones at the encoder, the 'upper' channel all-pass filter |
| factors (kUpperApFactors) are used to filter this new lower channel signal. |
| */ |
| WebRtcIsacfix_AllpassFilter2FixDec16(tempin_ch1, |
| tempin_ch2, |
| WebRtcIsacfix_kLowerApFactorsQ15, |
| WebRtcIsacfix_kUpperApFactorsQ15, |
| len / 2, |
| postfiltdata->STATE_0_UPPER_fix, |
| postfiltdata->STATE_0_LOWER_fix); |
| |
| /* Merge outputs to form the full length output signal.*/ |
| for (k=0;k<len/2;k++) { |
| in[2 * k] = tempin_ch2[k]; |
| in[2 * k + 1] = tempin_ch1[k]; |
| } |
| |
| /* High pass filter */ |
| WebRtcIsacfix_HighpassFilterFixDec32(in, len, WebRtcIsacfix_kHPStCoeffOut1Q30, postfiltdata->HPstates1_fix); |
| WebRtcIsacfix_HighpassFilterFixDec32(in, len, WebRtcIsacfix_kHPStCoeffOut2Q30, postfiltdata->HPstates2_fix); |
| |
| for (k=0;k<len;k++) { |
| out16[k] = in[k]; |
| } |
| } |
| |
| #endif |