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 function WebRtcSpl_ComplexFFT().
14 * The description header can be found in signal_processing_library.h
15 *
16 */
17
18#include "signal_processing_library.h"
19
20#define CFFTSFT 14
21#define CFFTRND 1
22#define CFFTRND2 16384
23
24#if (defined ARM9E_GCC) || (defined ARM_WINM) || (defined ANDROID_AECOPT)
25extern "C" int FFT_4OFQ14(void *src, void *dest, int NC, int shift);
26
27// For detailed description of the fft functions, check the readme files in fft_ARM9E folder.
28int WebRtcSpl_ComplexFFT2(WebRtc_Word16 frfi[], WebRtc_Word16 frfiOut[], int stages, int mode)
29{
30    return FFT_4OFQ14(frfi, frfiOut, 1 << stages, 0);
31}
32#endif
33
34int WebRtcSpl_ComplexFFT(WebRtc_Word16 frfi[], int stages, int mode)
35{
36    int i, j, l, k, istep, n, m;
37    WebRtc_Word16 wr, wi;
38    WebRtc_Word32 tr32, ti32, qr32, qi32;
39
40    /* The 1024-value is a constant given from the size of WebRtcSpl_kSinTable1024[],
41     * and should not be changed depending on the input parameter 'stages'
42     */
43    n = 1 << stages;
44    if (n > 1024)
45        return -1;
46
47    l = 1;
48    k = 10 - 1; /* Constant for given WebRtcSpl_kSinTable1024[]. Do not change
49         depending on the input parameter 'stages' */
50
51    if (mode == 0)
52    {
53        // mode==0: Low-complexity and Low-accuracy mode
54        while (l < n)
55        {
56            istep = l << 1;
57
58            for (m = 0; m < l; ++m)
59            {
60                j = m << k;
61
62                /* The 256-value is a constant given as 1/4 of the size of
63                 * WebRtcSpl_kSinTable1024[], and should not be changed depending on the input
64                 * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
65                 */
66                wr = WebRtcSpl_kSinTable1024[j + 256];
67                wi = -WebRtcSpl_kSinTable1024[j];
68
69                for (i = m; i < n; i += istep)
70                {
71                    j = i + l;
72
73                    tr32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j])
74                            - WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j + 1])), 15);
75
76                    ti32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1])
77                            + WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j])), 15);
78
79                    qr32 = (WebRtc_Word32)frfi[2 * i];
80                    qi32 = (WebRtc_Word32)frfi[2 * i + 1];
81                    frfi[2 * j] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qr32 - tr32, 1);
82                    frfi[2 * j + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qi32 - ti32, 1);
83                    frfi[2 * i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qr32 + tr32, 1);
84                    frfi[2 * i + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qi32 + ti32, 1);
85                }
86            }
87
88            --k;
89            l = istep;
90
91        }
92
93    } else
94    {
95        // mode==1: High-complexity and High-accuracy mode
96        while (l < n)
97        {
98            istep = l << 1;
99
100            for (m = 0; m < l; ++m)
101            {
102                j = m << k;
103
104                /* The 256-value is a constant given as 1/4 of the size of
105                 * WebRtcSpl_kSinTable1024[], and should not be changed depending on the input
106                 * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
107                 */
108                wr = WebRtcSpl_kSinTable1024[j + 256];
109                wi = -WebRtcSpl_kSinTable1024[j];
110
111                for (i = m; i < n; i += istep)
112                {
113                    j = i + l;
114
115                    tr32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j])
116                            - WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j + 1]) + CFFTRND),
117                            15 - CFFTSFT);
118
119                    ti32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1])
120                            + WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j]) + CFFTRND), 15 - CFFTSFT);
121
122                    qr32 = ((WebRtc_Word32)frfi[2 * i]) << CFFTSFT;
123                    qi32 = ((WebRtc_Word32)frfi[2 * i + 1]) << CFFTSFT;
124                    frfi[2 * j] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(
125                            (qr32 - tr32 + CFFTRND2), 1 + CFFTSFT);
126                    frfi[2 * j + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(
127                            (qi32 - ti32 + CFFTRND2), 1 + CFFTSFT);
128                    frfi[2 * i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(
129                            (qr32 + tr32 + CFFTRND2), 1 + CFFTSFT);
130                    frfi[2 * i + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(
131                            (qi32 + ti32 + CFFTRND2), 1 + CFFTSFT);
132                }
133            }
134
135            --k;
136            l = istep;
137        }
138    }
139    return 0;
140}
141