1885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/*********************************************************************** 2885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgCopyright (c) 2006-2011, Skype Limited. All rights reserved. 3885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgRedistribution and use in source and binary forms, with or without 4885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgmodification, are permitted provided that the following conditions 5885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgare met: 6885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org- Redistributions of source code must retain the above copyright notice, 7885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgthis list of conditions and the following disclaimer. 8885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org- Redistributions in binary form must reproduce the above copyright 9885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgnotice, this list of conditions and the following disclaimer in the 10885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgdocumentation and/or other materials provided with the distribution. 11e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org- Neither the name of Internet Society, IETF or IETF Trust, nor the 12885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgnames of specific contributors, may be used to endorse or promote 13885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgproducts derived from this software without specific prior written 14885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgpermission. 15e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgPOSSIBILITY OF SUCH DAMAGE. 26885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org***********************************************************************/ 27885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 28885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#ifdef HAVE_CONFIG_H 29885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "config.h" 30885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#endif 31885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 32885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* 33885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org Elliptic/Cauer filters designed with 0.1 dB passband ripple, 34885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 80 dB minimum stopband attenuation, and 35885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org [0.95 : 0.15 : 0.35] normalized cut off frequencies. 36885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org*/ 37885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 38885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "main.h" 39885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 40885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Helper function, interpolates the filter taps */ 413c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.comstatic OPUS_INLINE void silk_LP_interpolate_filter_taps( 42885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int32 B_Q28[ TRANSITION_NB ], 43885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int32 A_Q28[ TRANSITION_NA ], 44885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org const opus_int ind, 45885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org const opus_int32 fac_Q16 46885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org) 47885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{ 48885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int nb, na; 49885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 50885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( ind < TRANSITION_INT_NUM - 1 ) { 51885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( fac_Q16 > 0 ) { 52885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( fac_Q16 < 32768 ) { /* fac_Q16 is in range of a 16-bit int */ 53885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Piece-wise linear interpolation of B and A */ 54885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( nb = 0; nb < TRANSITION_NB; nb++ ) { 55885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org B_Q28[ nb ] = silk_SMLAWB( 56885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_Transition_LP_B_Q28[ ind ][ nb ], 57885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] - 58885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_Transition_LP_B_Q28[ ind ][ nb ], 59885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org fac_Q16 ); 60885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 61885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( na = 0; na < TRANSITION_NA; na++ ) { 62885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org A_Q28[ na ] = silk_SMLAWB( 63885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_Transition_LP_A_Q28[ ind ][ na ], 64885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_Transition_LP_A_Q28[ ind + 1 ][ na ] - 65885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_Transition_LP_A_Q28[ ind ][ na ], 66885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org fac_Q16 ); 67885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 68885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } else { /* ( fac_Q16 - ( 1 << 16 ) ) is in range of a 16-bit int */ 69885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_assert( fac_Q16 - ( 1 << 16 ) == silk_SAT16( fac_Q16 - ( 1 << 16 ) ) ); 70885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Piece-wise linear interpolation of B and A */ 71885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( nb = 0; nb < TRANSITION_NB; nb++ ) { 72885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org B_Q28[ nb ] = silk_SMLAWB( 73885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_Transition_LP_B_Q28[ ind + 1 ][ nb ], 74885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] - 75885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_Transition_LP_B_Q28[ ind ][ nb ], 76885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org fac_Q16 - ( (opus_int32)1 << 16 ) ); 77885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 78885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org for( na = 0; na < TRANSITION_NA; na++ ) { 79885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org A_Q28[ na ] = silk_SMLAWB( 80885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_Transition_LP_A_Q28[ ind + 1 ][ na ], 81885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_Transition_LP_A_Q28[ ind + 1 ][ na ] - 82885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_Transition_LP_A_Q28[ ind ][ na ], 83885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org fac_Q16 - ( (opus_int32)1 << 16 ) ); 84885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 85885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 86885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } else { 87885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ ind ], TRANSITION_NB * sizeof( opus_int32 ) ); 88885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ ind ], TRANSITION_NA * sizeof( opus_int32 ) ); 89885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 90885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } else { 91885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NB * sizeof( opus_int32 ) ); 92885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NA * sizeof( opus_int32 ) ); 93885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 94885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org} 95885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 96885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Low-pass filter with variable cutoff frequency based on */ 97885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* piece-wise linear interpolation between elliptic filters */ 98885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Start by setting psEncC->mode <> 0; */ 99885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Deactivate by setting psEncC->mode = 0; */ 100885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid silk_LP_variable_cutoff( 101885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_LP_state *psLP, /* I/O LP filter state */ 102885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int16 *frame, /* I/O Low-pass filtered output signal */ 103885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org const opus_int frame_length /* I Frame length */ 104885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org) 105885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{ 106885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int32 B_Q28[ TRANSITION_NB ], A_Q28[ TRANSITION_NA ], fac_Q16 = 0; 107885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org opus_int ind = 0; 108885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 109885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_assert( psLP->transition_frame_no >= 0 && psLP->transition_frame_no <= TRANSITION_FRAMES ); 110885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 111885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Run filter if needed */ 112885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org if( psLP->mode != 0 ) { 113885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Calculate index and interpolation factor for interpolation */ 114885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#if( TRANSITION_INT_STEPS == 64 ) 115885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org fac_Q16 = silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 - 6 ); 116885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#else 117885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org fac_Q16 = silk_DIV32_16( silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 ), TRANSITION_FRAMES ); 118885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#endif 119885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org ind = silk_RSHIFT( fac_Q16, 16 ); 120885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org fac_Q16 -= silk_LSHIFT( ind, 16 ); 121885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 122885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_assert( ind >= 0 ); 123885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_assert( ind < TRANSITION_INT_NUM ); 124885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 125885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Interpolate filter coefficients */ 126885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_LP_interpolate_filter_taps( B_Q28, A_Q28, ind, fac_Q16 ); 127885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 128885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* Update transition frame number for next frame */ 129885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org psLP->transition_frame_no = silk_LIMIT( psLP->transition_frame_no + psLP->mode, 0, TRANSITION_FRAMES ); 130885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org 131885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org /* ARMA low-pass filtering */ 132885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_assert( TRANSITION_NB == 3 && TRANSITION_NA == 2 ); 133885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org silk_biquad_alt( frame, B_Q28, A_Q28, psLP->In_LP_State, frame, frame_length, 1); 134885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org } 135885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org} 136