1 /*
2 * codec2_fft.c
3 *
4 * Created on: 24.09.2016
5 * Author: danilo
6 */
7
8 #include "codec2_fft.h"
9
10 #include "debug_alloc.h"
11
12 #ifdef USE_KISS_FFT
13 #include "_kiss_fft_guts.h"
14
15 #else
16 #if 0
17 // caching constants in RAM did not seem to have an effect on performance
18 // TODO: Decide what to with this code
19 #define FFT_INIT_CACHE_SIZE 4
20 const arm_cfft_instance_f32* fft_init_cache[FFT_INIT_CACHE_SIZE];
21
22 static const arm_cfft_instance_f32* arm_fft_instance2ram(const arm_cfft_instance_f32* in)
23 {
24
25 arm_cfft_instance_f32* out = malloc(sizeof(arm_cfft_instance_f32));
26
27 if (out) {
28 memcpy(out,in,sizeof(arm_cfft_instance_f32));
29 out->pBitRevTable = malloc(out->bitRevLength * sizeof(uint16_t));
30 out->pTwiddle = malloc(out->fftLen * sizeof(float32_t));
31 memcpy((void*)out->pBitRevTable,in->pBitRevTable,out->bitRevLength * sizeof(uint16_t));
32 memcpy((void*)out->pTwiddle,in->pTwiddle,out->fftLen * sizeof(float32_t));
33 }
34 return out;
35 }
36
37
38 static const arm_cfft_instance_f32* arm_fft_cache_get(const arm_cfft_instance_f32* romfft)
39 {
40 const arm_cfft_instance_f32* retval = NULL;
41 static int used = 0;
42 for (int i = 0; fft_init_cache[i] != NULL && i < used; i++)
43 {
44 if (romfft->fftLen == fft_init_cache[i]->fftLen)
45 {
46 retval = fft_init_cache[i];
47 break;
48 }
49 }
50 if (retval == NULL && used < FFT_INIT_CACHE_SIZE)
51 {
52 retval = arm_fft_instance2ram(romfft);
53 fft_init_cache[used++] = retval;
54 }
55 if (retval == NULL)
56 {
57 retval = romfft;
58 }
59 return retval;
60 }
61 #endif
62 #endif
63
codec2_fft_free(codec2_fft_cfg cfg)64 void codec2_fft_free(codec2_fft_cfg cfg)
65 {
66 #ifdef USE_KISS_FFT
67 KISS_FFT_FREE(cfg);
68 #else
69 FREE(cfg);
70 #endif
71 }
72
codec2_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem)73 codec2_fft_cfg codec2_fft_alloc(int nfft, int inverse_fft, void* mem, size_t* lenmem)
74 {
75 codec2_fft_cfg retval;
76 #ifdef USE_KISS_FFT
77 retval = kiss_fft_alloc(nfft, inverse_fft, mem, lenmem);
78 #else
79 retval = MALLOC(sizeof(codec2_fft_struct));
80 retval->inverse = inverse_fft;
81 switch(nfft)
82 {
83 case 128:
84 retval->instance = &arm_cfft_sR_f32_len128;
85 break;
86 case 256:
87 retval->instance = &arm_cfft_sR_f32_len256;
88 break;
89 case 512:
90 retval->instance = &arm_cfft_sR_f32_len512;
91 break;
92 // case 1024:
93 // retval->instance = &arm_cfft_sR_f32_len1024;
94 // break;
95 default:
96 abort();
97 }
98 // retval->instance = arm_fft_cache_get(retval->instance);
99 #endif
100 return retval;
101 }
102
codec2_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem)103 codec2_fftr_cfg codec2_fftr_alloc(int nfft, int inverse_fft, void* mem, size_t* lenmem)
104 {
105 codec2_fftr_cfg retval;
106 #ifdef USE_KISS_FFT
107 retval = kiss_fftr_alloc(nfft, inverse_fft, mem, lenmem);
108 #else
109 retval = MALLOC(sizeof(codec2_fftr_struct));
110 retval->inverse = inverse_fft;
111 retval->instance = MALLOC(sizeof(arm_rfft_fast_instance_f32));
112 arm_rfft_fast_init_f32(retval->instance,nfft);
113 // memcpy(&retval->instance->Sint,arm_fft_cache_get(&retval->instance->Sint),sizeof(arm_cfft_instance_f32));
114 #endif
115 return retval;
116 }
codec2_fftr_free(codec2_fftr_cfg cfg)117 void codec2_fftr_free(codec2_fftr_cfg cfg)
118 {
119 #ifdef USE_KISS_FFT
120 KISS_FFT_FREE(cfg);
121 #else
122 FREE(cfg->instance);
123 FREE(cfg);
124 #endif
125 }
126
127 // there is a little overhead for inplace kiss_fft but this is
128 // on the powerful platforms like the Raspberry or even x86 PC based ones
129 // not noticeable
130 // the reduced usage of RAM and increased performance on STM32 platforms
131 // should be worth it.
codec2_fft_inplace(codec2_fft_cfg cfg,codec2_fft_cpx * inout)132 void codec2_fft_inplace(codec2_fft_cfg cfg, codec2_fft_cpx* inout)
133 {
134
135 #ifdef USE_KISS_FFT
136 // decide whether to use the local stack based buffer for in
137 // or to allow kiss_fft to allocate RAM
138 // second part is just to play safe since first method
139 // is much faster and uses less RAM
140 if (cfg->nfft <= 512)
141 {
142 kiss_fft_cpx in[512];
143 memcpy(in,inout,cfg->nfft*sizeof(kiss_fft_cpx));
144 kiss_fft(cfg, in, (kiss_fft_cpx*)inout);
145 }
146 else
147 {
148 kiss_fft(cfg, (kiss_fft_cpx*)inout, (kiss_fft_cpx*)inout);
149 }
150 #else
151 arm_cfft_f32(cfg->instance,(float*)inout,cfg->inverse,1);
152 if (cfg->inverse)
153 {
154 arm_scale_f32((float*)inout,cfg->instance->fftLen,(float*)inout,cfg->instance->fftLen*2);
155 }
156
157 #endif
158 }
159