FreeCalypso > hg > gsm-codec-lib
comparison libtwamr/r_fft.c @ 412:810ac4b99025
libtwamr: integrate VAD2 r_fft.c
| author | Mychaela Falconia <falcon@freecalypso.org> |
|---|---|
| date | Tue, 07 May 2024 01:22:02 +0000 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 411:bd5614fc780a | 412:810ac4b99025 |
|---|---|
| 1 /* | |
| 2 ***************************************************************************** | |
| 3 * | |
| 4 * GSM AMR-NB speech codec R98 Version 7.6.0 December 12, 2001 | |
| 5 * R99 Version 3.3.0 | |
| 6 * REL-4 Version 4.1.0 | |
| 7 * | |
| 8 ***************************************************************************** | |
| 9 * | |
| 10 * File : r_fft.c | |
| 11 * Purpose : Fast Fourier Transform (FFT) algorithm | |
| 12 * | |
| 13 ***************************************************************************** | |
| 14 */ | |
| 15 | |
| 16 /***************************************************************** | |
| 17 * | |
| 18 * This is an implementation of decimation-in-time FFT algorithm for | |
| 19 * real sequences. The techniques used here can be found in several | |
| 20 * books, e.g., i) Proakis and Manolakis, "Digital Signal Processing", | |
| 21 * 2nd Edition, Chapter 9, and ii) W.H. Press et. al., "Numerical | |
| 22 * Recipes in C", 2nd Ediiton, Chapter 12. | |
| 23 * | |
| 24 * Input - There is one input to this function: | |
| 25 * | |
| 26 * 1) An integer pointer to the input data array | |
| 27 * | |
| 28 * Output - There is no return value. | |
| 29 * The input data are replaced with transformed data. If the | |
| 30 * input is a real time domain sequence, it is replaced with | |
| 31 * the complex FFT for positive frequencies. The FFT value | |
| 32 * for DC and the foldover frequency are combined to form the | |
| 33 * first complex number in the array. The remaining complex | |
| 34 * numbers correspond to increasing frequencies. If the input | |
| 35 * is a complex frequency domain sequence arranged as above, | |
| 36 * it is replaced with the corresponding time domain sequence. | |
| 37 * | |
| 38 * Notes: | |
| 39 * | |
| 40 * 1) This function is designed to be a part of a VAD | |
| 41 * algorithm that requires 128-point FFT of real | |
| 42 * sequences. This is achieved here through a 64-point | |
| 43 * complex FFT. Consequently, the FFT size information is | |
| 44 * not transmitted explicitly. However, some flexibility | |
| 45 * is provided in the function to change the size of the | |
| 46 * FFT by specifying the size information through "define" | |
| 47 * statements. | |
| 48 * | |
| 49 * 2) The values of the complex sinusoids used in the FFT | |
| 50 * algorithm are stored in a ROM table. | |
| 51 * | |
| 52 * 3) In the c_fft function, the FFT values are divided by | |
| 53 * 2 after each stage of computation thus dividing the | |
| 54 * final FFT values by 64. This is somewhat different | |
| 55 * from the usual definition of FFT where the factor 1/N, | |
| 56 * i.e., 1/64, used for the IFFT and not the FFT. No factor | |
| 57 * is used in the r_fft function. | |
| 58 * | |
| 59 *****************************************************************/ | |
| 60 | |
| 61 #include "tw_amr.h" | |
| 62 #include "namespace.h" | |
| 63 #include "typedef.h" | |
| 64 #include "cnst.h" | |
| 65 #include "basic_op.h" | |
| 66 #include "oper_32b.h" | |
| 67 #include "no_count.h" | |
| 68 #include "vad2.h" | |
| 69 | |
| 70 #define SIZE 128 | |
| 71 #define SIZE_BY_TWO 64 | |
| 72 #define NUM_STAGE 6 | |
| 73 #define TRUE 1 | |
| 74 #define FALSE 0 | |
| 75 | |
| 76 static const Word16 phs_tbl[] = | |
| 77 { | |
| 78 | |
| 79 32767, 0, 32729, -1608, 32610, -3212, 32413, -4808, | |
| 80 32138, -6393, 31786, -7962, 31357, -9512, 30853, -11039, | |
| 81 30274, -12540, 29622, -14010, 28899, -15447, 28106, -16846, | |
| 82 27246, -18205, 26320, -19520, 25330, -20788, 24279, -22006, | |
| 83 23170, -23170, 22006, -24279, 20788, -25330, 19520, -26320, | |
| 84 18205, -27246, 16846, -28106, 15447, -28899, 14010, -29622, | |
| 85 12540, -30274, 11039, -30853, 9512, -31357, 7962, -31786, | |
| 86 6393, -32138, 4808, -32413, 3212, -32610, 1608, -32729, | |
| 87 0, -32768, -1608, -32729, -3212, -32610, -4808, -32413, | |
| 88 -6393, -32138, -7962, -31786, -9512, -31357, -11039, -30853, | |
| 89 -12540, -30274, -14010, -29622, -15447, -28899, -16846, -28106, | |
| 90 -18205, -27246, -19520, -26320, -20788, -25330, -22006, -24279, | |
| 91 -23170, -23170, -24279, -22006, -25330, -20788, -26320, -19520, | |
| 92 -27246, -18205, -28106, -16846, -28899, -15447, -29622, -14010, | |
| 93 -30274, -12540, -30853, -11039, -31357, -9512, -31786, -7962, | |
| 94 -32138, -6393, -32413, -4808, -32610, -3212, -32729, -1608 | |
| 95 | |
| 96 }; | |
| 97 | |
| 98 static const Word16 ii_table[] = | |
| 99 {SIZE / 2, SIZE / 4, SIZE / 8, SIZE / 16, SIZE / 32, SIZE / 64}; | |
| 100 | |
| 101 /* FFT function for complex sequences */ | |
| 102 | |
| 103 /* | |
| 104 * The decimation-in-time complex FFT is implemented below. | |
| 105 * The input complex numbers are presented as real part followed by | |
| 106 * imaginary part for each sample. The counters are therefore | |
| 107 * incremented by two to access the complex valued samples. | |
| 108 */ | |
| 109 | |
| 110 static void c_fft(Word16 * farray_ptr) | |
| 111 { | |
| 112 | |
| 113 Word16 i, j, k, ii, jj, kk, ji, kj, ii2; | |
| 114 Word32 ftmp, ftmp_real, ftmp_imag; | |
| 115 Word16 tmp, tmp1, tmp2; | |
| 116 | |
| 117 /* Rearrange the input array in bit reversed order */ | |
| 118 for (i = 0, j = 0; i < SIZE - 2; i = i + 2) | |
| 119 { test(); | |
| 120 if (sub(j, i) > 0) | |
| 121 { | |
| 122 ftmp = *(farray_ptr + i); move16(); | |
| 123 *(farray_ptr + i) = *(farray_ptr + j); move16(); | |
| 124 *(farray_ptr + j) = ftmp; move16(); | |
| 125 | |
| 126 ftmp = *(farray_ptr + i + 1); move16(); | |
| 127 *(farray_ptr + i + 1) = *(farray_ptr + j + 1); move16(); | |
| 128 *(farray_ptr + j + 1) = ftmp; move16(); | |
| 129 } | |
| 130 | |
| 131 k = SIZE_BY_TWO; move16(); | |
| 132 test(); | |
| 133 while (sub(j, k) >= 0) | |
| 134 { | |
| 135 j = sub(j, k); | |
| 136 k = shr(k, 1); | |
| 137 } | |
| 138 j = add(j, k); | |
| 139 } | |
| 140 | |
| 141 /* The FFT part */ | |
| 142 for (i = 0; i < NUM_STAGE; i++) | |
| 143 { /* i is stage counter */ | |
| 144 jj = shl(2, i); /* FFT size */ | |
| 145 kk = shl(jj, 1); /* 2 * FFT size */ | |
| 146 ii = ii_table[i]; /* 2 * number of FFT's */ move16(); | |
| 147 ii2 = shl(ii, 1); | |
| 148 ji = 0; /* ji is phase table index */ move16(); | |
| 149 | |
| 150 for (j = 0; j < jj; j = j + 2) | |
| 151 { /* j is sample counter */ | |
| 152 | |
| 153 for (k = j; k < SIZE; k = k + kk) | |
| 154 { /* k is butterfly top */ | |
| 155 kj = add(k, jj); /* kj is butterfly bottom */ | |
| 156 | |
| 157 /* Butterfly computations */ | |
| 158 ftmp_real = L_mult(*(farray_ptr + kj), phs_tbl[ji]); | |
| 159 ftmp_real = L_msu(ftmp_real, *(farray_ptr + kj + 1), phs_tbl[ji + 1]); | |
| 160 | |
| 161 ftmp_imag = L_mult(*(farray_ptr + kj + 1), phs_tbl[ji]); | |
| 162 ftmp_imag = L_mac(ftmp_imag, *(farray_ptr + kj), phs_tbl[ji + 1]); | |
| 163 | |
| 164 tmp1 = round(ftmp_real); | |
| 165 tmp2 = round(ftmp_imag); | |
| 166 | |
| 167 tmp = sub(*(farray_ptr + k), tmp1); | |
| 168 *(farray_ptr + kj) = shr(tmp, 1); move16(); | |
| 169 | |
| 170 tmp = sub(*(farray_ptr + k + 1), tmp2); | |
| 171 *(farray_ptr + kj + 1) = shr(tmp, 1); move16(); | |
| 172 | |
| 173 tmp = add(*(farray_ptr + k), tmp1); | |
| 174 *(farray_ptr + k) = shr(tmp, 1); move16(); | |
| 175 | |
| 176 tmp = add(*(farray_ptr + k + 1), tmp2); | |
| 177 *(farray_ptr + k + 1) = shr(tmp, 1); move16(); | |
| 178 } | |
| 179 | |
| 180 ji = add(ji, ii2); | |
| 181 } | |
| 182 } | |
| 183 } /* end of c_fft () */ | |
| 184 | |
| 185 | |
| 186 | |
| 187 void r_fft(Word16 * farray_ptr) | |
| 188 { | |
| 189 | |
| 190 Word16 ftmp1_real, ftmp1_imag, ftmp2_real, ftmp2_imag; | |
| 191 Word32 Lftmp1_real, Lftmp1_imag; | |
| 192 Word16 i, j; | |
| 193 Word32 Ltmp1; | |
| 194 | |
| 195 /* Perform the complex FFT */ | |
| 196 c_fft(farray_ptr); | |
| 197 | |
| 198 /* First, handle the DC and foldover frequencies */ | |
| 199 ftmp1_real = *farray_ptr; move16(); | |
| 200 ftmp2_real = *(farray_ptr + 1); move16(); | |
| 201 *farray_ptr = add(ftmp1_real, ftmp2_real); move16(); | |
| 202 *(farray_ptr + 1) = sub(ftmp1_real, ftmp2_real); move16(); | |
| 203 | |
| 204 /* Now, handle the remaining positive frequencies */ | |
| 205 for (i = 2, j = SIZE - i; i <= SIZE_BY_TWO; i = i + 2, j = SIZE - i) | |
| 206 { | |
| 207 ftmp1_real = add(*(farray_ptr + i), *(farray_ptr + j)); | |
| 208 ftmp1_imag = sub(*(farray_ptr + i + 1), *(farray_ptr + j + 1)); | |
| 209 ftmp2_real = add(*(farray_ptr + i + 1), *(farray_ptr + j + 1)); | |
| 210 ftmp2_imag = sub(*(farray_ptr + j), *(farray_ptr + i)); | |
| 211 | |
| 212 Lftmp1_real = L_deposit_h(ftmp1_real); | |
| 213 Lftmp1_imag = L_deposit_h(ftmp1_imag); | |
| 214 | |
| 215 Ltmp1 = L_mac(Lftmp1_real, ftmp2_real, phs_tbl[i]); | |
| 216 Ltmp1 = L_msu(Ltmp1, ftmp2_imag, phs_tbl[i + 1]); | |
| 217 *(farray_ptr + i) = round(L_shr(Ltmp1, 1)); move16(); | |
| 218 | |
| 219 Ltmp1 = L_mac(Lftmp1_imag, ftmp2_imag, phs_tbl[i]); | |
| 220 Ltmp1 = L_mac(Ltmp1, ftmp2_real, phs_tbl[i + 1]); | |
| 221 *(farray_ptr + i + 1) = round(L_shr(Ltmp1, 1)); move16(); | |
| 222 | |
| 223 Ltmp1 = L_mac(Lftmp1_real, ftmp2_real, phs_tbl[j]); | |
| 224 Ltmp1 = L_mac(Ltmp1, ftmp2_imag, phs_tbl[j + 1]); | |
| 225 *(farray_ptr + j) = round(L_shr(Ltmp1, 1)); move16(); | |
| 226 | |
| 227 Ltmp1 = L_negate(Lftmp1_imag); | |
| 228 Ltmp1 = L_msu(Ltmp1, ftmp2_imag, phs_tbl[j]); | |
| 229 Ltmp1 = L_mac(Ltmp1, ftmp2_real, phs_tbl[j + 1]); | |
| 230 *(farray_ptr + j + 1) = round(L_shr(Ltmp1, 1)); move16(); | |
| 231 | |
| 232 } | |
| 233 } /* end r_fft () */ |
