summaryrefslogtreecommitdiff
path: root/codec2_fft.c
blob: 7a75062e068c451f12a1eb33e97ead91fd983013 (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
/*
 * 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
  // 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) {
    kiss_fft_cpx in[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
}