Line data Source code
1 : /******************************************************************************
2 : * ETSI TS 103 634 V1.5.1 *
3 : * Low Complexity Communication Codec Plus (LC3plus) *
4 : * *
5 : * Copyright licence is solely granted through ETSI Intellectual Property *
6 : * Rights Policy, 3rd April 2019. No patent licence is granted by implication, *
7 : * estoppel or otherwise. *
8 : ******************************************************************************/
9 :
10 : #include "options.h"
11 : #include "wmc_auto.h"
12 : #include <assert.h>
13 : #include <stddef.h>
14 : #include <stdio.h>
15 : #include <stdlib.h>
16 : #include <string.h>
17 : #include <math.h>
18 : #include "iis_fft.h"
19 :
20 : /**************************************************************************************************/
21 :
22 : /* AFFT uses two fft implementations
23 : * cfft is used for lengths of power of two, >= 256.
24 : * iisfft is used for everything else. it is optimized for certain lengths. for a list of
25 : fast lengths, check the fft_n function.
26 : */
27 :
28 : #define FFT_COMPLEX 1
29 : #define FFT_REAL 2
30 :
31 :
32 0 : static IIS_FFT_ERROR create(HANDLE_IIS_FFT* handle, LC3_INT type, LC3_INT len, IIS_FFT_DIR sign)
33 : {
34 0 : IIS_FFT_ERROR err = IIS_FFT_MEMORY_ERROR;
35 :
36 : /* for real transforms the actual performed fft is half length */
37 0 : LC3_INT trlen = (type == FFT_COMPLEX) ? len : len / 2;
38 :
39 : /* check argument sanity */
40 0 : if ((sign != IIS_FFT_FWD) && (sign != IIS_FFT_BWD))
41 : {
42 0 : return IIS_FFT_INTERNAL_ERROR;
43 : }
44 :
45 :
46 0 : if (!(*handle))
47 : {
48 0 : (*handle) = (HANDLE_IIS_FFT)calloc(1, sizeof(IIS_FFT));
49 : }
50 0 : if (!(*handle))
51 : {
52 0 : return IIS_FFT_MEMORY_ERROR;
53 : }
54 :
55 0 : (*handle)->len = len;
56 0 : (*handle)->sign = sign;
57 :
58 : /* create sine lookup table for real ffts */
59 0 : if (type == FFT_REAL)
60 : {
61 0 : LC3_create_sine_table(len, (*handle)->sine_table);
62 0 : if (!(*handle)->sine_table)
63 : {
64 0 : goto handle_error1;
65 : }
66 : }
67 :
68 : /* set default cfft_plan to 0(length). (and default iisfft_plan to zero length) */
69 0 : (*handle)->cfft.len = 0; /* 0 length means that cfft should not be called */
70 0 : (*handle)->iisfft.length = 0; /*saftey setting for iisfft length struct */
71 :
72 : /* use cfft for legth of power two larger than 256. for length below iisfft is faster */
73 0 : if (trlen >= 256 && CFFT_PLAN_SUPPORT(trlen)) {
74 0 : LC3_INT s = (type == FFT_REAL) ? IIS_FFT_FWD : sign;
75 0 : err = LC3_cfft_plan(&(*handle)->cfft, trlen, s) ? IIS_FFT_NO_ERROR : IIS_FFT_INTERNAL_ERROR;
76 : } else {
77 0 : LC3_INT s = (type == FFT_REAL) ? IIS_FFT_FWD : sign;
78 0 : err = LC3_iisfft_plan(&(*handle)->iisfft, trlen, s);
79 : }
80 :
81 0 : return IIS_FFT_NO_ERROR;
82 :
83 0 : handle_error1:
84 0 : free((*handle));
85 :
86 0 : return err;
87 : }
88 :
89 0 : IIS_FFT_ERROR LC3_IIS_RFFT_Create(HANDLE_IIS_FFT* handle, LC3_INT32 len, IIS_FFT_DIR sign)
90 : {
91 0 : return create(handle, FFT_REAL, len, sign);
92 : }
93 :
94 0 : static IIS_FFT_ERROR destroy(HANDLE_IIS_FFT* handle)
95 : {
96 0 : if (handle && *handle) {
97 0 : LC3_iisfft_free(&(*handle)->iisfft);
98 0 : LC3_cfft_free(&(*handle)->cfft);
99 0 : free(*handle);
100 0 : *handle = NULL;
101 : }
102 0 : return IIS_FFT_NO_ERROR;
103 : }
104 :
105 0 : IIS_FFT_ERROR LC3_IIS_CFFT_Create(HANDLE_IIS_FFT* handle, LC3_INT len, IIS_FFT_DIR sign)
106 : {
107 0 : return create(handle, FFT_COMPLEX, len, sign);
108 : }
109 :
110 :
111 0 : IIS_FFT_ERROR LC3_IIS_xFFT_Destroy(HANDLE_IIS_FFT* handle) { return destroy(handle); }
112 :
113 0 : IIS_FFT_ERROR LC3_IIS_CFFT_Destroy(HANDLE_IIS_FFT* handle) { return destroy(handle); }
114 :
115 0 : static IIS_FFT_ERROR real_destroy(HANDLE_IIS_FFT* handle)
116 : {
117 0 : if (handle && *handle) {
118 0 : LC3_iisfft_free(&(*handle)->iisfft);
119 0 : *handle = NULL;
120 : }
121 0 : return IIS_FFT_NO_ERROR;
122 : }
123 :
124 0 : IIS_FFT_ERROR LC3_IIS_RFFT_Destroy(HANDLE_IIS_FFT* handle) { return real_destroy(handle); }
125 :
126 0 : IIS_FFT_ERROR LC3_IIS_FFT_Apply_CFFT(HANDLE_IIS_FFT handle, const Complex* input, Complex* output)
127 : {
128 : LC3_FLOAT* dummy;
129 0 : if (!handle)
130 : {
131 0 : return IIS_FFT_INTERNAL_ERROR;
132 : }
133 :
134 : /* check for inplace operation */
135 0 : memmove(output, input, sizeof(*input) * handle->len);
136 0 : dummy = (LC3_FLOAT*)output;
137 0 : if (handle->cfft.len > 0) {
138 0 : LC3_cfft_apply(&handle->cfft, dummy, dummy + 1, 2);
139 : } else {
140 0 : LC3_iisfft_apply(&handle->iisfft, dummy);
141 : }
142 :
143 0 : return IIS_FFT_NO_ERROR;
144 : }
145 :
146 :
147 0 : IIS_FFT_ERROR LC3_IIS_FFT_Apply_RFFT(HANDLE_IIS_FFT handle, const LC3_FLOAT* in, LC3_FLOAT* out)
148 : {
149 0 : if (!handle) {
150 0 : return IIS_FFT_INTERNAL_ERROR;
151 : }
152 :
153 0 : memmove(out, in, sizeof(LC3_FLOAT) * handle->len);
154 :
155 0 : if (handle->sign == IIS_FFT_BWD) {
156 0 : LC3_rfft_pre(handle->sine_table, out, handle->len);
157 : }
158 :
159 0 : if (handle->cfft.len > 0) {
160 0 : LC3_cfft_apply(&handle->cfft, out, out + 1, 2);
161 : }
162 : else {
163 0 : LC3_iisfft_apply(&handle->iisfft, out);
164 : }
165 :
166 0 : if (handle->sign == IIS_FFT_FWD) {
167 0 : LC3_rfft_post(handle->sine_table, out, handle->len);
168 : }
169 :
170 0 : return IIS_FFT_NO_ERROR;
171 : }
|