Home | History | Annotate | Download | only in signal_processing
      1 /*
      2  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 
     12 /*
     13  * This file contains the resampling by two functions.
     14  * The description header can be found in signal_processing_library.h
     15  *
     16  */
     17 
     18 #include "signal_processing_library.h"
     19 
     20 #ifdef WEBRTC_ARCH_ARM_V7A
     21 
     22 // allpass filter coefficients.
     23 static const WebRtc_UWord32 kResampleAllpass1[3] = {3284, 24441, 49528 << 15};
     24 static const WebRtc_UWord32 kResampleAllpass2[3] =
     25   {12199, 37471 << 15, 60255 << 15};
     26 
     27 // Multiply two 32-bit values and accumulate to another input value.
     28 // Return: state + ((diff * tbl_value) >> 16)
     29 
     30 static __inline WebRtc_Word32 MUL_ACCUM_1(WebRtc_Word32 tbl_value,
     31                                           WebRtc_Word32 diff,
     32                                           WebRtc_Word32 state) {
     33   WebRtc_Word32 result;
     34   __asm__("smlawb %r0, %r1, %r2, %r3": "=r"(result): "r"(diff),
     35                                        "r"(tbl_value), "r"(state));
     36   return result;
     37 }
     38 
     39 // Multiply two 32-bit values and accumulate to another input value.
     40 // Return: Return: state + (((diff << 1) * tbl_value) >> 32)
     41 //
     42 // The reason to introduce this function is that, in case we can't use smlawb
     43 // instruction (in MUL_ACCUM_1) due to input value range, we can still use
     44 // smmla to save some cycles.
     45 
     46 static __inline WebRtc_Word32 MUL_ACCUM_2(WebRtc_Word32 tbl_value,
     47                                           WebRtc_Word32 diff,
     48                                           WebRtc_Word32 state) {
     49   WebRtc_Word32 result;
     50   __asm__("smmla %r0, %r1, %r2, %r3": "=r"(result): "r"(diff << 1),
     51                                       "r"(tbl_value), "r"(state));
     52   return result;
     53 }
     54 
     55 #else
     56 
     57 // allpass filter coefficients.
     58 static const WebRtc_UWord16 kResampleAllpass1[3] = {3284, 24441, 49528};
     59 static const WebRtc_UWord16 kResampleAllpass2[3] = {12199, 37471, 60255};
     60 
     61 // Multiply a 32-bit value with a 16-bit value and accumulate to another input:
     62 #define MUL_ACCUM_1(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c)
     63 #define MUL_ACCUM_2(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c)
     64 
     65 #endif  // WEBRTC_ARCH_ARM_V7A
     66 
     67 
     68 // decimator
     69 void WebRtcSpl_DownsampleBy2(const WebRtc_Word16* in, const WebRtc_Word16 len,
     70                              WebRtc_Word16* out, WebRtc_Word32* filtState) {
     71   WebRtc_Word32 tmp1, tmp2, diff, in32, out32;
     72   WebRtc_Word16 i;
     73 
     74   register WebRtc_Word32 state0 = filtState[0];
     75   register WebRtc_Word32 state1 = filtState[1];
     76   register WebRtc_Word32 state2 = filtState[2];
     77   register WebRtc_Word32 state3 = filtState[3];
     78   register WebRtc_Word32 state4 = filtState[4];
     79   register WebRtc_Word32 state5 = filtState[5];
     80   register WebRtc_Word32 state6 = filtState[6];
     81   register WebRtc_Word32 state7 = filtState[7];
     82 
     83   for (i = (len >> 1); i > 0; i--) {
     84     // lower allpass filter
     85     in32 = (WebRtc_Word32)(*in++) << 10;
     86     diff = in32 - state1;
     87     tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0);
     88     state0 = in32;
     89     diff = tmp1 - state2;
     90     tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1);
     91     state1 = tmp1;
     92     diff = tmp2 - state3;
     93     state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2);
     94     state2 = tmp2;
     95 
     96     // upper allpass filter
     97     in32 = (WebRtc_Word32)(*in++) << 10;
     98     diff = in32 - state5;
     99     tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4);
    100     state4 = in32;
    101     diff = tmp1 - state6;
    102     tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5);
    103     state5 = tmp1;
    104     diff = tmp2 - state7;
    105     state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6);
    106     state6 = tmp2;
    107 
    108     // add two allpass outputs, divide by two and round
    109     out32 = (state3 + state7 + 1024) >> 11;
    110 
    111     // limit amplitude to prevent wrap-around, and write to output array
    112     *out++ = WebRtcSpl_SatW32ToW16(out32);
    113   }
    114 
    115   filtState[0] = state0;
    116   filtState[1] = state1;
    117   filtState[2] = state2;
    118   filtState[3] = state3;
    119   filtState[4] = state4;
    120   filtState[5] = state5;
    121   filtState[6] = state6;
    122   filtState[7] = state7;
    123 }
    124 
    125 
    126 void WebRtcSpl_UpsampleBy2(const WebRtc_Word16* in, WebRtc_Word16 len,
    127                            WebRtc_Word16* out, WebRtc_Word32* filtState) {
    128   WebRtc_Word32 tmp1, tmp2, diff, in32, out32;
    129   WebRtc_Word16 i;
    130 
    131   register WebRtc_Word32 state0 = filtState[0];
    132   register WebRtc_Word32 state1 = filtState[1];
    133   register WebRtc_Word32 state2 = filtState[2];
    134   register WebRtc_Word32 state3 = filtState[3];
    135   register WebRtc_Word32 state4 = filtState[4];
    136   register WebRtc_Word32 state5 = filtState[5];
    137   register WebRtc_Word32 state6 = filtState[6];
    138   register WebRtc_Word32 state7 = filtState[7];
    139 
    140   for (i = len; i > 0; i--) {
    141     // lower allpass filter
    142     in32 = (WebRtc_Word32)(*in++) << 10;
    143     diff = in32 - state1;
    144     tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state0);
    145     state0 = in32;
    146     diff = tmp1 - state2;
    147     tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state1);
    148     state1 = tmp1;
    149     diff = tmp2 - state3;
    150     state3 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state2);
    151     state2 = tmp2;
    152 
    153     // round; limit amplitude to prevent wrap-around; write to output array
    154     out32 = (state3 + 512) >> 10;
    155     *out++ = WebRtcSpl_SatW32ToW16(out32);
    156 
    157     // upper allpass filter
    158     diff = in32 - state5;
    159     tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state4);
    160     state4 = in32;
    161     diff = tmp1 - state6;
    162     tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state5);
    163     state5 = tmp1;
    164     diff = tmp2 - state7;
    165     state7 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state6);
    166     state6 = tmp2;
    167 
    168     // round; limit amplitude to prevent wrap-around; write to output array
    169     out32 = (state7 + 512) >> 10;
    170     *out++ = WebRtcSpl_SatW32ToW16(out32);
    171   }
    172 
    173   filtState[0] = state0;
    174   filtState[1] = state1;
    175   filtState[2] = state2;
    176   filtState[3] = state3;
    177   filtState[4] = state4;
    178   filtState[5] = state5;
    179   filtState[6] = state6;
    180   filtState[7] = state7;
    181 }
    182