| /* | 
 |  *  Copyright (c) 2011 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. | 
 |  */ | 
 |  | 
 |  | 
 | /* | 
 |  * This file contains the function WebRtcSpl_ComplexFFT(). | 
 |  * The description header can be found in signal_processing_library.h | 
 |  * | 
 |  */ | 
 |  | 
 | #include "common_audio/signal_processing/complex_fft_tables.h" | 
 | #include "common_audio/signal_processing/include/signal_processing_library.h" | 
 | #include "rtc_base/system/arch.h" | 
 |  | 
 | #define CFFTSFT 14 | 
 | #define CFFTRND 1 | 
 | #define CFFTRND2 16384 | 
 |  | 
 | #define CIFFTSFT 14 | 
 | #define CIFFTRND 1 | 
 |  | 
 |  | 
 | int WebRtcSpl_ComplexFFT(int16_t frfi[], int stages, int mode) | 
 | { | 
 |     int i, j, l, k, istep, n, m; | 
 |     int16_t wr, wi; | 
 |     int32_t tr32, ti32, qr32, qi32; | 
 |  | 
 |     /* The 1024-value is a constant given from the size of kSinTable1024[], | 
 |      * and should not be changed depending on the input parameter 'stages' | 
 |      */ | 
 |     n = 1 << stages; | 
 |     if (n > 1024) | 
 |         return -1; | 
 |  | 
 |     l = 1; | 
 |     k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change | 
 |          depending on the input parameter 'stages' */ | 
 |  | 
 |     if (mode == 0) | 
 |     { | 
 |         // mode==0: Low-complexity and Low-accuracy mode | 
 |         while (l < n) | 
 |         { | 
 |             istep = l << 1; | 
 |  | 
 |             for (m = 0; m < l; ++m) | 
 |             { | 
 |                 j = m << k; | 
 |  | 
 |                 /* The 256-value is a constant given as 1/4 of the size of | 
 |                  * kSinTable1024[], and should not be changed depending on the input | 
 |                  * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 | 
 |                  */ | 
 |                 wr = kSinTable1024[j + 256]; | 
 |                 wi = -kSinTable1024[j]; | 
 |  | 
 |                 for (i = m; i < n; i += istep) | 
 |                 { | 
 |                     j = i + l; | 
 |  | 
 |                     tr32 = (wr * frfi[2 * j] - wi * frfi[2 * j + 1]) >> 15; | 
 |  | 
 |                     ti32 = (wr * frfi[2 * j + 1] + wi * frfi[2 * j]) >> 15; | 
 |  | 
 |                     qr32 = (int32_t)frfi[2 * i]; | 
 |                     qi32 = (int32_t)frfi[2 * i + 1]; | 
 |                     frfi[2 * j] = (int16_t)((qr32 - tr32) >> 1); | 
 |                     frfi[2 * j + 1] = (int16_t)((qi32 - ti32) >> 1); | 
 |                     frfi[2 * i] = (int16_t)((qr32 + tr32) >> 1); | 
 |                     frfi[2 * i + 1] = (int16_t)((qi32 + ti32) >> 1); | 
 |                 } | 
 |             } | 
 |  | 
 |             --k; | 
 |             l = istep; | 
 |  | 
 |         } | 
 |  | 
 |     } else | 
 |     { | 
 |         // mode==1: High-complexity and High-accuracy mode | 
 |         while (l < n) | 
 |         { | 
 |             istep = l << 1; | 
 |  | 
 |             for (m = 0; m < l; ++m) | 
 |             { | 
 |                 j = m << k; | 
 |  | 
 |                 /* The 256-value is a constant given as 1/4 of the size of | 
 |                  * kSinTable1024[], and should not be changed depending on the input | 
 |                  * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 | 
 |                  */ | 
 |                 wr = kSinTable1024[j + 256]; | 
 |                 wi = -kSinTable1024[j]; | 
 |  | 
 | #ifdef WEBRTC_ARCH_ARM_V7 | 
 |                 int32_t wri = 0; | 
 |                 __asm __volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) : | 
 |                     "r"((int32_t)wr), "r"((int32_t)wi)); | 
 | #endif | 
 |  | 
 |                 for (i = m; i < n; i += istep) | 
 |                 { | 
 |                     j = i + l; | 
 |  | 
 | #ifdef WEBRTC_ARCH_ARM_V7 | 
 |                     register int32_t frfi_r; | 
 |                     __asm __volatile( | 
 |                         "pkhbt %[frfi_r], %[frfi_even], %[frfi_odd]," | 
 |                         " lsl #16\n\t" | 
 |                         "smlsd %[tr32], %[wri], %[frfi_r], %[cfftrnd]\n\t" | 
 |                         "smladx %[ti32], %[wri], %[frfi_r], %[cfftrnd]\n\t" | 
 |                         :[frfi_r]"=&r"(frfi_r), | 
 |                          [tr32]"=&r"(tr32), | 
 |                          [ti32]"=r"(ti32) | 
 |                         :[frfi_even]"r"((int32_t)frfi[2*j]), | 
 |                          [frfi_odd]"r"((int32_t)frfi[2*j +1]), | 
 |                          [wri]"r"(wri), | 
 |                          [cfftrnd]"r"(CFFTRND)); | 
 | #else | 
 |                     tr32 = wr * frfi[2 * j] - wi * frfi[2 * j + 1] + CFFTRND; | 
 |  | 
 |                     ti32 = wr * frfi[2 * j + 1] + wi * frfi[2 * j] + CFFTRND; | 
 | #endif | 
 |  | 
 |                     tr32 >>= 15 - CFFTSFT; | 
 |                     ti32 >>= 15 - CFFTSFT; | 
 |  | 
 |                     qr32 = ((int32_t)frfi[2 * i]) * (1 << CFFTSFT); | 
 |                     qi32 = ((int32_t)frfi[2 * i + 1]) * (1 << CFFTSFT); | 
 |  | 
 |                     frfi[2 * j] = (int16_t)( | 
 |                         (qr32 - tr32 + CFFTRND2) >> (1 + CFFTSFT)); | 
 |                     frfi[2 * j + 1] = (int16_t)( | 
 |                         (qi32 - ti32 + CFFTRND2) >> (1 + CFFTSFT)); | 
 |                     frfi[2 * i] = (int16_t)( | 
 |                         (qr32 + tr32 + CFFTRND2) >> (1 + CFFTSFT)); | 
 |                     frfi[2 * i + 1] = (int16_t)( | 
 |                         (qi32 + ti32 + CFFTRND2) >> (1 + CFFTSFT)); | 
 |                 } | 
 |             } | 
 |  | 
 |             --k; | 
 |             l = istep; | 
 |         } | 
 |     } | 
 |     return 0; | 
 | } | 
 |  | 
 | int WebRtcSpl_ComplexIFFT(int16_t frfi[], int stages, int mode) | 
 | { | 
 |     size_t i, j, l, istep, n, m; | 
 |     int k, scale, shift; | 
 |     int16_t wr, wi; | 
 |     int32_t tr32, ti32, qr32, qi32; | 
 |     int32_t tmp32, round2; | 
 |  | 
 |     /* The 1024-value is a constant given from the size of kSinTable1024[], | 
 |      * and should not be changed depending on the input parameter 'stages' | 
 |      */ | 
 |     n = ((size_t)1) << stages; | 
 |     if (n > 1024) | 
 |         return -1; | 
 |  | 
 |     scale = 0; | 
 |  | 
 |     l = 1; | 
 |     k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change | 
 |          depending on the input parameter 'stages' */ | 
 |  | 
 |     while (l < n) | 
 |     { | 
 |         // variable scaling, depending upon data | 
 |         shift = 0; | 
 |         round2 = 8192; | 
 |  | 
 |         tmp32 = WebRtcSpl_MaxAbsValueW16(frfi, 2 * n); | 
 |         if (tmp32 > 13573) | 
 |         { | 
 |             shift++; | 
 |             scale++; | 
 |             round2 <<= 1; | 
 |         } | 
 |         if (tmp32 > 27146) | 
 |         { | 
 |             shift++; | 
 |             scale++; | 
 |             round2 <<= 1; | 
 |         } | 
 |  | 
 |         istep = l << 1; | 
 |  | 
 |         if (mode == 0) | 
 |         { | 
 |             // mode==0: Low-complexity and Low-accuracy mode | 
 |             for (m = 0; m < l; ++m) | 
 |             { | 
 |                 j = m << k; | 
 |  | 
 |                 /* The 256-value is a constant given as 1/4 of the size of | 
 |                  * kSinTable1024[], and should not be changed depending on the input | 
 |                  * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 | 
 |                  */ | 
 |                 wr = kSinTable1024[j + 256]; | 
 |                 wi = kSinTable1024[j]; | 
 |  | 
 |                 for (i = m; i < n; i += istep) | 
 |                 { | 
 |                     j = i + l; | 
 |  | 
 |                     tr32 = (wr * frfi[2 * j] - wi * frfi[2 * j + 1]) >> 15; | 
 |  | 
 |                     ti32 = (wr * frfi[2 * j + 1] + wi * frfi[2 * j]) >> 15; | 
 |  | 
 |                     qr32 = (int32_t)frfi[2 * i]; | 
 |                     qi32 = (int32_t)frfi[2 * i + 1]; | 
 |                     frfi[2 * j] = (int16_t)((qr32 - tr32) >> shift); | 
 |                     frfi[2 * j + 1] = (int16_t)((qi32 - ti32) >> shift); | 
 |                     frfi[2 * i] = (int16_t)((qr32 + tr32) >> shift); | 
 |                     frfi[2 * i + 1] = (int16_t)((qi32 + ti32) >> shift); | 
 |                 } | 
 |             } | 
 |         } else | 
 |         { | 
 |             // mode==1: High-complexity and High-accuracy mode | 
 |  | 
 |             for (m = 0; m < l; ++m) | 
 |             { | 
 |                 j = m << k; | 
 |  | 
 |                 /* The 256-value is a constant given as 1/4 of the size of | 
 |                  * kSinTable1024[], and should not be changed depending on the input | 
 |                  * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 | 
 |                  */ | 
 |                 wr = kSinTable1024[j + 256]; | 
 |                 wi = kSinTable1024[j]; | 
 |  | 
 | #ifdef WEBRTC_ARCH_ARM_V7 | 
 |                 int32_t wri = 0; | 
 |                 __asm __volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) : | 
 |                     "r"((int32_t)wr), "r"((int32_t)wi)); | 
 | #endif | 
 |  | 
 |                 for (i = m; i < n; i += istep) | 
 |                 { | 
 |                     j = i + l; | 
 |  | 
 | #ifdef WEBRTC_ARCH_ARM_V7 | 
 |                     register int32_t frfi_r; | 
 |                     __asm __volatile( | 
 |                       "pkhbt %[frfi_r], %[frfi_even], %[frfi_odd], lsl #16\n\t" | 
 |                       "smlsd %[tr32], %[wri], %[frfi_r], %[cifftrnd]\n\t" | 
 |                       "smladx %[ti32], %[wri], %[frfi_r], %[cifftrnd]\n\t" | 
 |                       :[frfi_r]"=&r"(frfi_r), | 
 |                        [tr32]"=&r"(tr32), | 
 |                        [ti32]"=r"(ti32) | 
 |                       :[frfi_even]"r"((int32_t)frfi[2*j]), | 
 |                        [frfi_odd]"r"((int32_t)frfi[2*j +1]), | 
 |                        [wri]"r"(wri), | 
 |                        [cifftrnd]"r"(CIFFTRND) | 
 |                     ); | 
 | #else | 
 |  | 
 |                     tr32 = wr * frfi[2 * j] - wi * frfi[2 * j + 1] + CIFFTRND; | 
 |  | 
 |                     ti32 = wr * frfi[2 * j + 1] + wi * frfi[2 * j] + CIFFTRND; | 
 | #endif | 
 |                     tr32 >>= 15 - CIFFTSFT; | 
 |                     ti32 >>= 15 - CIFFTSFT; | 
 |  | 
 |                     qr32 = ((int32_t)frfi[2 * i]) * (1 << CIFFTSFT); | 
 |                     qi32 = ((int32_t)frfi[2 * i + 1]) * (1 << CIFFTSFT); | 
 |  | 
 |                     frfi[2 * j] = (int16_t)( | 
 |                         (qr32 - tr32 + round2) >> (shift + CIFFTSFT)); | 
 |                     frfi[2 * j + 1] = (int16_t)( | 
 |                         (qi32 - ti32 + round2) >> (shift + CIFFTSFT)); | 
 |                     frfi[2 * i] = (int16_t)( | 
 |                         (qr32 + tr32 + round2) >> (shift + CIFFTSFT)); | 
 |                     frfi[2 * i + 1] = (int16_t)( | 
 |                         (qi32 + ti32 + round2) >> (shift + CIFFTSFT)); | 
 |                 } | 
 |             } | 
 |  | 
 |         } | 
 |         --k; | 
 |         l = istep; | 
 |     } | 
 |     return scale; | 
 | } |