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