summaryrefslogtreecommitdiff
path: root/codec2_fft.c
blob: 14b867008fab2ce0111315b3a30aec34a3612e6c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*
 * codec2_fft.c
 *
 *  Created on: 24.09.2016
 *      Author: danilo
 */

#include "codec2_fft.h"

#include "debug_alloc.h"

#ifdef USE_KISS_FFT
#include "_kiss_fft_guts.h"

#else
#if 0
// caching constants in RAM did not seem to have an effect on performance
// TODO: Decide what to with this code
#define FFT_INIT_CACHE_SIZE 4
const arm_cfft_instance_f32* fft_init_cache[FFT_INIT_CACHE_SIZE];

static const arm_cfft_instance_f32* arm_fft_instance2ram(const arm_cfft_instance_f32* in)
{

    arm_cfft_instance_f32* out = malloc(sizeof(arm_cfft_instance_f32));

    if (out) {
        memcpy(out,in,sizeof(arm_cfft_instance_f32));
        out->pBitRevTable = malloc(out->bitRevLength * sizeof(uint16_t));
        out->pTwiddle = malloc(out->fftLen * sizeof(float32_t));
        memcpy((void*)out->pBitRevTable,in->pBitRevTable,out->bitRevLength * sizeof(uint16_t));
        memcpy((void*)out->pTwiddle,in->pTwiddle,out->fftLen * sizeof(float32_t));
    }
    return out;
}


static const arm_cfft_instance_f32* arm_fft_cache_get(const arm_cfft_instance_f32* romfft)
{
    const arm_cfft_instance_f32* retval = NULL;
    static int used = 0;
    for (int i = 0; fft_init_cache[i] != NULL && i < used; i++)
    {
        if (romfft->fftLen == fft_init_cache[i]->fftLen)
        {
            retval = fft_init_cache[i];
            break;
        }
    }
    if (retval == NULL && used < FFT_INIT_CACHE_SIZE)
    {
         retval = arm_fft_instance2ram(romfft);
         fft_init_cache[used++] = retval;
    }
    if (retval == NULL)
    {
        retval = romfft;
    }
    return retval;
}
#endif
#endif

void codec2_fft_free(codec2_fft_cfg cfg)
{
#ifdef USE_KISS_FFT
    KISS_FFT_FREE(cfg);
#else
    FREE(cfg);
#endif
}

codec2_fft_cfg codec2_fft_alloc(int nfft, int inverse_fft, void* mem, size_t* lenmem)
{
    codec2_fft_cfg retval;
#ifdef USE_KISS_FFT
    retval = kiss_fft_alloc(nfft, inverse_fft, mem, lenmem);
#else
    retval = MALLOC(sizeof(codec2_fft_struct));
    retval->inverse  = inverse_fft;
    switch(nfft)
    {
    case 128:
        retval->instance = &arm_cfft_sR_f32_len128;
        break;
    case 256:
        retval->instance = &arm_cfft_sR_f32_len256;
        break;
    case 512:
        retval->instance = &arm_cfft_sR_f32_len512;
        break;
//    case 1024:
//        retval->instance = &arm_cfft_sR_f32_len1024;
//        break;
    default:
        abort();
    }
    // retval->instance = arm_fft_cache_get(retval->instance);
#endif
    return retval;
}

codec2_fftr_cfg codec2_fftr_alloc(int nfft, int inverse_fft, void* mem, size_t* lenmem)
{
    codec2_fftr_cfg retval;
#ifdef USE_KISS_FFT
    retval = kiss_fftr_alloc(nfft, inverse_fft, mem, lenmem);
#else
    retval = MALLOC(sizeof(codec2_fftr_struct));
    retval->inverse  = inverse_fft;
    retval->instance = MALLOC(sizeof(arm_rfft_fast_instance_f32));
    arm_rfft_fast_init_f32(retval->instance,nfft);
    // memcpy(&retval->instance->Sint,arm_fft_cache_get(&retval->instance->Sint),sizeof(arm_cfft_instance_f32));
#endif
    return retval;
}
void codec2_fftr_free(codec2_fftr_cfg cfg)
{
#ifdef USE_KISS_FFT
    KISS_FFT_FREE(cfg);
#else
    FREE(cfg->instance);
    FREE(cfg);
#endif
}

// there is a little overhead for inplace kiss_fft but this is
// on the powerful platforms like the Raspberry or even x86 PC based ones
// not noticeable
// the reduced usage of RAM and increased performance on STM32 platforms
// should be worth it.
void codec2_fft_inplace(codec2_fft_cfg cfg, codec2_fft_cpx* inout)
{

#ifdef USE_KISS_FFT
    kiss_fft_cpx in[512];
    // decide whether to use the local stack based buffer for in
    // or to allow kiss_fft to allocate RAM
    // second part is just to play safe since first method
    // is much faster and uses less RAM
    if (cfg->nfft <= 512)
    {
        memcpy(in,inout,cfg->nfft*sizeof(kiss_fft_cpx));
        kiss_fft(cfg, in, (kiss_fft_cpx*)inout);
    }
    else
    {
        kiss_fft(cfg, (kiss_fft_cpx*)inout, (kiss_fft_cpx*)inout);
    }
#else
    arm_cfft_f32(cfg->instance,(float*)inout,cfg->inverse,1);
    if (cfg->inverse)
    {
        arm_scale_f32((float*)inout,cfg->instance->fftLen,(float*)inout,cfg->instance->fftLen*2);
    }

#endif
}