blob: 68d51b9fae21a7a8bb385e1e45fac0f600818dff [file] [log] [blame]
/*
* 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 <assert.h>
#include "codec.h"
#include "filterbank_tables.h"
#include "settings.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.
assert(length % 2 == 0);
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; // Q15 -> Q16
b = WebRtcSpl_AddSatW32(a, state0_ch1);
a = -factor_ch1[0] * (int16_t)(b >> 16); // Q15
state0_ch1 = WebRtcSpl_AddSatW32(a << 1, (uint32_t)in_out << 16); // Q16
in_out = (int16_t) (b >> 16); // Save as Q0
a = factor_ch1[1] * in_out; // Q15 * Q0 = Q15
a <<= 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, (uint32_t)in_out << 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; // Q15 -> Q16
b = WebRtcSpl_AddSatW32(a, state0_ch2); // Q16
a = -factor_ch2[0] * (int16_t)(b >> 16); // Q15
state0_ch2 = WebRtcSpl_AddSatW32(a << 1, (uint32_t)in_out << 16); // Q16
in_out = (int16_t) (b >> 16); // Save as Q0
a = factor_ch2[1] * in_out; // Q15 * Q0 = Q15
a <<= 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, (uint32_t)in_out << 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 = WEBRTC_SPL_LSHIFT_W32((int32_t)in, 2) - a2 - b2; // In Q2.
c = (int32_t)WEBRTC_SPL_SAT(536870911, c, -536870912);
state1 = state0;
state0 = WEBRTC_SPL_LSHIFT_W32(c, 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