diff --git a/src/modules/audio_coding/codecs/isac/fix/source/filterbank_internal.h b/src/modules/audio_coding/codecs/isac/fix/source/filterbank_internal.h new file mode 100644 index 0000000000..d5d9efbe16 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/filterbank_internal.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_FILTERBANK_INTERNAL_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_FILTERBANK_INTERNAL_H_ + +#include "typedefs.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* Arguments: + * io: Input/output, in Q0. + * len: Input, sample length. + * coefficient: Input. + * state: Input/output, filter state, in Q4. + */ +void WebRtcIsacfix_HighpassFilterFixDec32(int16_t *io, + int16_t len, + const int16_t *coefficient, + int32_t *state); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif +/* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_FILTERBANK_INTERNAL_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/fix/source/filterbank_tables.h b/src/modules/audio_coding/codecs/isac/fix/source/filterbank_tables.h index 2dadc063d4..9a888e4fc6 100644 --- a/src/modules/audio_coding/codecs/isac/fix/source/filterbank_tables.h +++ b/src/modules/audio_coding/codecs/isac/fix/source/filterbank_tables.h @@ -21,6 +21,10 @@ #include "typedefs.h" +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + /********************* Coefficient Tables ************************/ /* HPstcoeff_in_Q14 = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */ @@ -41,4 +45,8 @@ extern const int16_t WebRtcIsacfix_kUpperApFactorsQ15[2]; /* The lower channel all-pass filter factors */ extern const int16_t WebRtcIsacfix_kLowerApFactorsQ15[2]; +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + #endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_FILTERBANK_TABLES_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/fix/source/filterbanks.c b/src/modules/audio_coding/codecs/isac/fix/source/filterbanks.c index 6f9d85f508..457815d839 100644 --- a/src/modules/audio_coding/codecs/isac/fix/source/filterbanks.c +++ b/src/modules/audio_coding/codecs/isac/fix/source/filterbanks.c @@ -19,6 +19,7 @@ */ #include "codec.h" +#include "filterbank_internal.h" #include "filterbank_tables.h" #include "settings.h" @@ -49,11 +50,10 @@ static void AllpassFilter2FixDec16(WebRtc_Word16 *InOut16, //Q0 } -static void HighpassFilterFixDec32( - WebRtc_Word16 *io, /* Q0:input Q0: Output */ - WebRtc_Word16 len, /* length of input, Input */ - const WebRtc_Word16 *coeff, /* Coeff: [Q30hi Q30lo Q30hi Q30lo Q35hi Q35lo Q35hi Q35lo] */ - WebRtc_Word32 *state) /* Q4:filter state Input/Output */ +void WebRtcIsacfix_HighpassFilterFixDec32(int16_t *io, + int16_t len, + const int16_t *coefficient, + int32_t *state) { int k; WebRtc_Word32 a1 = 0, b1 = 0, c = 0, in = 0; @@ -66,34 +66,36 @@ static void HighpassFilterFixDec32( #ifdef WEBRTC_ARCH_ARM_V7A { - int tmp_coeff = 0; + int tmp_coeff0 = 0; + int tmp_coeff1 = 0; __asm __volatile( - "ldr %[tmp_coeff], [%[coeff]]\n\t" - "smmulr %[a2], %[tmp_coeff], %[state0]\n\t" - "ldr %[tmp_coeff], [%[coeff], #4]\n\t" - "smmulr %[b2], %[tmp_coeff], %[state1]\n\t" - "ldr %[tmp_coeff], [%[coeff], #8]\n\t" - "smmulr %[a1], %[tmp_coeff], %[state0]\n\t" - "ldr %[tmp_coeff], [%[coeff], #12]\n\t" - "smmulr %[b1], %[tmp_coeff], %[state1]\n\t" + "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_coeff]"+r"(tmp_coeff) - :[coeff]"r"(coeff), + [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_32_32_RSFT32(coeff[5], coeff[4], state0); - b1 = WEBRTC_SPL_MUL_32_32_RSFT32(coeff[7], coeff[6], state1); + a1 = WEBRTC_SPL_MUL_32_32_RSFT32(coefficient[5], coefficient[4], state0); + b1 = WEBRTC_SPL_MUL_32_32_RSFT32(coefficient[7], coefficient[6], state1); /* Q30 * Q4 = Q34 ; shift 32 bit => Q2 */ - a2 = WEBRTC_SPL_MUL_32_32_RSFT32(coeff[1], coeff[0], state0); - b2 = WEBRTC_SPL_MUL_32_32_RSFT32(coeff[3], coeff[2], state1); + a2 = WEBRTC_SPL_MUL_32_32_RSFT32(coefficient[1], coefficient[0], state0); + b2 = WEBRTC_SPL_MUL_32_32_RSFT32(coefficient[3], coefficient[2], state1); #endif c = ((WebRtc_Word32)in) + WEBRTC_SPL_RSHIFT_W32(a1+b1, 7); // Q0 @@ -127,7 +129,7 @@ void WebRtcIsacfix_SplitAndFilter1(WebRtc_Word16 *pin, /* High pass filter */ - HighpassFilterFixDec32(pin, FRAMESAMPLES, WebRtcIsacfix_kHpStCoeffInQ30, prefiltdata->HPstates_fix); + WebRtcIsacfix_HighpassFilterFixDec32(pin, FRAMESAMPLES, WebRtcIsacfix_kHpStCoeffInQ30, prefiltdata->HPstates_fix); /* First Channel */ @@ -197,7 +199,7 @@ void WebRtcIsacfix_SplitAndFilter2(WebRtc_Word16 *pin, /* High pass filter */ - HighpassFilterFixDec32(pin, FRAMESAMPLES, WebRtcIsacfix_kHpStCoeffInQ30, prefiltdata->HPstates_fix); + WebRtcIsacfix_HighpassFilterFixDec32(pin, FRAMESAMPLES, WebRtcIsacfix_kHpStCoeffInQ30, prefiltdata->HPstates_fix); /* First Channel */ @@ -284,8 +286,8 @@ void WebRtcIsacfix_FilterAndCombine1(WebRtc_Word16 *tempin_ch1, } /* High pass filter */ - HighpassFilterFixDec32(in, FRAMESAMPLES, WebRtcIsacfix_kHPStCoeffOut1Q30, postfiltdata->HPstates1_fix); - HighpassFilterFixDec32(in, FRAMESAMPLES, WebRtcIsacfix_kHPStCoeffOut2Q30, postfiltdata->HPstates2_fix); + WebRtcIsacfix_HighpassFilterFixDec32(in, FRAMESAMPLES, WebRtcIsacfix_kHPStCoeffOut1Q30, postfiltdata->HPstates1_fix); + WebRtcIsacfix_HighpassFilterFixDec32(in, FRAMESAMPLES, WebRtcIsacfix_kHPStCoeffOut2Q30, postfiltdata->HPstates2_fix); for (k=0;kHPstates1_fix); - HighpassFilterFixDec32(in, len, WebRtcIsacfix_kHPStCoeffOut2Q30, postfiltdata->HPstates2_fix); + WebRtcIsacfix_HighpassFilterFixDec32(in, len, WebRtcIsacfix_kHPStCoeffOut1Q30, postfiltdata->HPstates1_fix); + WebRtcIsacfix_HighpassFilterFixDec32(in, len, WebRtcIsacfix_kHPStCoeffOut2Q30, postfiltdata->HPstates2_fix); for (k=0;k #include "gtest/gtest.h" +#include "modules/audio_coding/codecs/isac/fix/source/filterbank_internal.h" +#include "modules/audio_coding/codecs/isac/fix/source/filterbank_tables.h" #include "modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.h" #include "system_wrappers/interface/cpu_features_wrapper.h" @@ -66,3 +68,29 @@ TEST_F(IsacUnitTest, CalculateResidualEnergyTest) { CalculateResidualEnergyTester(WebRtcIsacfix_CalculateResidualEnergyNeon); #endif } + +TEST_F(IsacUnitTest, HighpassFilterFixDec32Test) { + const int kSamples = 20; + int16_t in[kSamples]; + int32_t state[2] = {12345, 987654}; +#ifdef WEBRTC_ARCH_ARM_V7A + int32_t out[kSamples] = {-1040, -1035, -22875, -1397, -27604, 20018, 7917, + -1279, -8552, -14494, -7558, -23537, -27258, -30554, -32768, -3432, -32768, + 25215, -27536, 22436}; +#else + int32_t out[kSamples] = {-1040, -1035, -22875, -1397, -27604, 20017, 7915, + -1280, -8554, -14496, -7561, -23541, -27263, -30560, -32768, -3441, -32768, + 25203, -27550, 22419}; +#endif + + for(int i = 0; i < kSamples; i++) { + in[i] = WEBRTC_SPL_WORD32_MAX / (i + 1); + } + + WebRtcIsacfix_HighpassFilterFixDec32(in, kSamples, + WebRtcIsacfix_kHPStCoeffOut1Q30, state); + + for(int i = 0; i < kSamples; i++) { + EXPECT_EQ(out[i], in[i]); + } +}