├── CMakeLists.txt ├── LICENSE ├── README.md ├── dr_mp3.h ├── dr_wav.h ├── main.c ├── stb_fft.h └── timing.h /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | project(FFTResampler LANGUAGES C) 3 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 4 | SET(CMAKE_BUILD_TYPE "Release") 5 | 6 | include_directories(include) 7 | add_executable(${PROJECT_NAME} main.c) 8 | 9 | target_link_libraries(${PROJECT_NAME} -lm) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Zhihan Gao 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FFTResampler 2 | A Simple and Efficient Implementation Of Fast Fourier Transform For Audio Resampler 3 | 4 | 5 | # Donating 6 | 7 | If you found this project useful, consider buying me a coffee 8 | 9 | Buy Me A Coffee 10 | 11 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | 2 | #ifdef __cplusplus 3 | extern "C" { 4 | #endif 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #define DR_WAV_IMPLEMENTATION 11 | 12 | #include "dr_wav.h" 13 | 14 | #define DR_MP3_IMPLEMENTATION 15 | 16 | 17 | #include "dr_mp3.h" 18 | 19 | #include "timing.h" 20 | 21 | 22 | #define STB_FFT_IMPLEMENTAION 23 | 24 | #include "stb_fft.h" 25 | 26 | #ifndef max 27 | #define max(a, b) ((a) > (b) ? (a) : (b)) 28 | #endif 29 | 30 | 31 | void wavWrite_f32(char *filename, float *buffer, int sampleRate, uint32_t totalSampleCount, uint32_t channels) 32 | { 33 | drwav_data_format format; 34 | format.container = drwav_container_riff; 35 | format.format = DR_WAVE_FORMAT_IEEE_FLOAT; 36 | format.channels = channels; 37 | format.sampleRate = (drwav_uint32) sampleRate; 38 | format.bitsPerSample = 32; 39 | drwav *pWav = drwav_open_file_write(filename, &format); 40 | if (pWav) { 41 | drwav_uint64 samplesWritten = drwav_write(pWav, totalSampleCount, buffer); 42 | drwav_uninit(pWav); 43 | if (samplesWritten != totalSampleCount) { 44 | fprintf(stderr, "write file [%s] error.\n", filename); 45 | exit(1); 46 | } 47 | } 48 | } 49 | 50 | float *wavRead_f32(const char *filename, uint32_t *sampleRate, uint64_t *sampleCount, uint32_t *channels) 51 | { 52 | drwav_uint64 totalSampleCount = 0; 53 | float *input = drwav_open_file_and_read_pcm_frames_f32(filename, channels, sampleRate, &totalSampleCount); 54 | if (input == NULL) { 55 | drmp3_config pConfig; 56 | input = drmp3_open_file_and_read_f32(filename, &pConfig, &totalSampleCount); 57 | if (input != NULL) { 58 | *channels = pConfig.outputChannels; 59 | *sampleRate = pConfig.outputSampleRate; 60 | } 61 | } 62 | if (input == NULL) { 63 | fprintf(stderr, "read file [%s] error.\n", filename); 64 | exit(1); 65 | } 66 | *sampleCount = totalSampleCount * (*channels); 67 | return input; 68 | } 69 | 70 | void splitpath(const char *path, char *drv, char *dir, char *name, char *ext) 71 | { 72 | const char *end; 73 | const char *p; 74 | const char *s; 75 | if (path[0] && path[1] == ':') { 76 | if (drv) { 77 | *drv++ = *path++; 78 | *drv++ = *path++; 79 | *drv = '\0'; 80 | } 81 | } 82 | else if (drv) 83 | *drv = '\0'; 84 | for (end = path; *end && *end != ':';) 85 | end++; 86 | for (p = end; p > path && *--p != '\\' && *p != '/';) 87 | if (*p == '.') { 88 | end = p; 89 | break; 90 | } 91 | if (ext) 92 | for (s = end; (*ext = *s++);) 93 | ext++; 94 | for (p = end; p > path;) 95 | if (*--p == '\\' || *p == '/') { 96 | p++; 97 | break; 98 | } 99 | if (name) { 100 | for (s = p; s < end;) 101 | *name++ = *s++; 102 | *name = '\0'; 103 | } 104 | if (dir) { 105 | for (s = path; s < p;) 106 | *dir++ = *s++; 107 | *dir = '\0'; 108 | } 109 | } 110 | 111 | typedef struct 112 | { 113 | int inFrameSize; 114 | int inWindowSize; 115 | int inSampleRate; 116 | float *inWindowing; 117 | stb_fft_real_plan *inPlan; 118 | int outFrameSize; 119 | int outWindowSize; 120 | int outSampleRate; 121 | float *outWindowing; 122 | stb_fft_real_plan *outPlan; 123 | float *inFifo; 124 | float *synthesisMem; 125 | cmplx *samples; 126 | int pos; 127 | } FFT_Resampler_Handle; 128 | 129 | void FFT_Resampler_Free(FFT_Resampler_Handle *handle) 130 | { 131 | if (handle) { 132 | if (handle->inFifo) { 133 | free(handle->inFifo); 134 | handle->inFifo = NULL; 135 | } 136 | 137 | if (handle->inPlan) { 138 | free(handle->inPlan); 139 | handle->inPlan = NULL; 140 | } 141 | 142 | if (handle->outPlan) { 143 | free(handle->outPlan); 144 | handle->outPlan = NULL; 145 | } 146 | 147 | if (handle->samples) { 148 | free(handle->samples); 149 | handle->samples = NULL; 150 | } 151 | 152 | if (handle->synthesisMem) { 153 | free(handle->synthesisMem); 154 | handle->synthesisMem = NULL; 155 | } 156 | 157 | if (handle->inWindowing) { 158 | free(handle->inWindowing); 159 | handle->inWindowing = NULL; 160 | } 161 | 162 | if (handle->outWindowing) { 163 | free(handle->outWindowing); 164 | handle->outWindowing = NULL; 165 | } 166 | } 167 | } 168 | 169 | void FFT_Resampler_reset(FFT_Resampler_Handle *handle) 170 | { 171 | if (handle) 172 | handle->pos = 0; 173 | } 174 | 175 | int FFT_Resampler_Init(FFT_Resampler_Handle *handle, size_t inSampleRate, size_t outSampleRate, size_t nFFT) 176 | { 177 | if (handle) { 178 | handle->pos = 0; 179 | if (outSampleRate < inSampleRate) { 180 | nFFT = nFFT * inSampleRate * 128 / outSampleRate; 181 | } 182 | else { 183 | nFFT = nFFT * outSampleRate * 128 / inSampleRate; 184 | } 185 | nFFT += (nFFT % 2); 186 | handle->inFrameSize = nFFT; 187 | handle->inWindowSize = nFFT * 2; 188 | handle->inSampleRate = inSampleRate; 189 | handle->inWindowing = (float *) calloc(handle->inFrameSize, sizeof(float)); 190 | handle->inPlan = stb_fft_real_plan_dft_1d(handle->inWindowSize); 191 | handle->outSampleRate = outSampleRate; 192 | handle->outFrameSize = handle->inFrameSize * outSampleRate / inSampleRate; 193 | handle->outWindowSize = handle->outFrameSize * 2; 194 | handle->outWindowing = (float *) calloc(handle->outFrameSize, sizeof(float)); 195 | handle->outPlan = stb_fft_real_plan_dft_1d(handle->outWindowSize); 196 | handle->inFifo = (float *) calloc(max(handle->inWindowSize, handle->outWindowSize), sizeof(float)); 197 | handle->samples = (cmplx *) calloc(max(handle->inWindowSize, handle->outWindowSize), sizeof(cmplx)); 198 | handle->synthesisMem = (float *) calloc(handle->outFrameSize, sizeof(float)); 199 | if ((handle->inFifo == NULL) || (handle->inPlan == NULL) || (handle->outPlan == NULL) 200 | || (handle->samples == NULL) 201 | || (handle->synthesisMem == NULL) || (handle->inWindowing == NULL) || (handle->outWindowing == NULL) 202 | ) { 203 | FFT_Resampler_Free(handle); 204 | return 0; 205 | } 206 | float norm = 1.0f / handle->inWindowSize; 207 | for (size_t i = 0; i < handle->inFrameSize; i++) { 208 | double t = sin(.5 * M_PI * (i + .5) / handle->inFrameSize); 209 | handle->inWindowing[i] = (float) sin(.5 * M_PI * t * t) * norm; 210 | } 211 | for (size_t i = 0; i < handle->outFrameSize; i++) { 212 | double t = sin(.5 * M_PI * (i + .5) / handle->outFrameSize); 213 | handle->outWindowing[i] = (float) sin(.5 * M_PI * t * t); 214 | } 215 | return 1; 216 | } 217 | return 0; 218 | } 219 | 220 | int FFT_Resampler_Proc(FFT_Resampler_Handle *handle, const float *input, float *output) 221 | { 222 | if ((input == NULL) || (handle == NULL) || (output == NULL)) { 223 | return -1; 224 | } 225 | float *inFifo = handle->inFifo; 226 | float *synthesis_mem = handle->synthesisMem; 227 | for (size_t i = 0; i < handle->inFrameSize; i++) { 228 | inFifo[i] *= handle->inWindowing[i]; 229 | inFifo[handle->inWindowSize - 1 - i] = input[handle->inFrameSize - 1 - i] * handle->inWindowing[i]; 230 | } 231 | stb_fft_r2c_exec(handle->inPlan, inFifo, handle->samples); 232 | if (handle->outWindowSize < handle->inWindowSize) { 233 | int half_output = (handle->outWindowSize / 2); 234 | int diff_size = handle->inWindowSize - handle->outWindowSize; 235 | memset(handle->samples + half_output, 0, diff_size * sizeof(cmplx)); 236 | } 237 | else if (handle->outWindowSize > handle->inWindowSize) { 238 | int half_input = handle->inWindowSize / 2; 239 | int diff_size = handle->outWindowSize - handle->inWindowSize; 240 | memmove(handle->samples + half_input + diff_size, handle->samples + half_input, 241 | half_input * sizeof(cmplx)); 242 | memset(handle->samples + half_input, 0, diff_size * sizeof(cmplx)); 243 | } 244 | stb_fft_c2r_exec(handle->outPlan, handle->samples, inFifo); 245 | for (size_t i = 0; i < handle->outFrameSize; i++) { 246 | output[i] = inFifo[i] * handle->outWindowing[i] + synthesis_mem[i]; 247 | inFifo[handle->outWindowSize - 1 - i] *= handle->outWindowing[i]; 248 | } 249 | memcpy(synthesis_mem, inFifo + handle->outFrameSize, handle->outFrameSize * sizeof(float)); 250 | memcpy(inFifo, input, handle->inFrameSize * sizeof(float)); 251 | if (handle->pos == 0) { 252 | handle->pos++; 253 | return 0; 254 | } 255 | handle->pos++; 256 | return 1; 257 | } 258 | 259 | void printUsage() 260 | { 261 | printf("usage:\n"); 262 | printf("./FFTResampler input.wav 48000\n"); 263 | printf("./FFTResampler input.mp3 16000\n"); 264 | printf("or\n"); 265 | printf("./FFTResampler input.wav output.wav 8000\n"); 266 | printf("./FFTResampler input.mp3 output.wav 44100\n"); 267 | printf("press any key to exit.\n"); 268 | getchar(); 269 | } 270 | 271 | void FFT_Resampler(char *in_file, char *out_file, uint32_t targetSampleRate) 272 | { 273 | if (targetSampleRate == 0) { 274 | printUsage(); 275 | return; 276 | } 277 | uint32_t sampleRate = 0; 278 | uint64_t sampleCount = 0; 279 | uint32_t channels = 0; 280 | float *input = wavRead_f32(in_file, &sampleRate, &sampleCount, &channels); 281 | if (input) { 282 | size_t nFFT = 2; 283 | FFT_Resampler_Handle *handle = (FFT_Resampler_Handle *) malloc(sizeof(FFT_Resampler_Handle)); 284 | if (handle) { 285 | double startTime = now(); 286 | if (FFT_Resampler_Init(handle, sampleRate, targetSampleRate, nFFT) == 1) { 287 | uint64_t frames = (sampleCount / handle->inFrameSize); 288 | int remainingSample = (sampleCount % handle->inFrameSize); 289 | int outRemainingSize = remainingSample * targetSampleRate / sampleRate; 290 | uint64_t targetSampleCount = frames * handle->outFrameSize + outRemainingSize; 291 | float *output = (float *) calloc(targetSampleCount, sizeof(float)); 292 | if (output) { 293 | FFT_Resampler_reset(handle); 294 | float *inBuffer = input; 295 | float *outBuffer = output; 296 | for (int n = 0; n < frames; ++n) { 297 | if (FFT_Resampler_Proc(handle, inBuffer, outBuffer) == 1) 298 | outBuffer += handle->outFrameSize; 299 | inBuffer += handle->inFrameSize; 300 | } 301 | if (remainingSample == 0) { 302 | inBuffer -= handle->inFrameSize; 303 | FFT_Resampler_Proc(handle, inBuffer, outBuffer); 304 | memcpy(outBuffer, handle->synthesisMem, sizeof(float) * handle->outFrameSize); 305 | } 306 | else { 307 | float *buffer = (float *) calloc(handle->inFrameSize, sizeof(float)); 308 | if (buffer) { 309 | memcpy(buffer, inBuffer, sizeof(float) * remainingSample); 310 | if (FFT_Resampler_Proc(handle, buffer, outBuffer) == 1) 311 | outBuffer += handle->outFrameSize; 312 | free(buffer); 313 | 314 | memcpy(outBuffer, handle->synthesisMem, sizeof(float) * outRemainingSize); 315 | } 316 | } 317 | } 318 | double time_interval = calcElapsed(startTime, now()); 319 | printf("time interval: %f ms\n ", (time_interval * 1000)); 320 | wavWrite_f32(out_file, output, targetSampleRate, (uint32_t) targetSampleCount, channels); 321 | free(output); 322 | } 323 | FFT_Resampler_Free(handle); 324 | free(handle); 325 | } 326 | free(input); 327 | } 328 | } 329 | 330 | int main(int argc, char *argv[]) 331 | { 332 | printf("Audio Processing\n"); 333 | printf("blog:http://cpuimage.cnblogs.com/\n"); 334 | printf("Audio FFT Resampler\n"); 335 | if (argc < 3) { 336 | printUsage(); 337 | return -1; 338 | } 339 | char *in_file = argv[1]; 340 | if (argc > 3) { 341 | char *out_file = argv[2]; 342 | uint32_t targetSampleRate = (uint32_t) atoi(argv[3]); 343 | FFT_Resampler(in_file, out_file, targetSampleRate); 344 | } 345 | else { 346 | int32_t targetSampleRate = (uint32_t) atoi(argv[2]); 347 | char drive[3]; 348 | char dir[256]; 349 | char fname[256]; 350 | char ext[256]; 351 | char out_file[1024]; 352 | splitpath(in_file, drive, dir, fname, ext); 353 | sprintf(out_file, "%s%s%s_out.wav", drive, dir, fname); 354 | FFT_Resampler(in_file, out_file, targetSampleRate); 355 | } 356 | 357 | return 0; 358 | } 359 | 360 | #ifdef __cplusplus 361 | } 362 | #endif 363 | -------------------------------------------------------------------------------- /stb_fft.h: -------------------------------------------------------------------------------- 1 | // fast fourier transform library (suitable for power of 2 and non-power of 2) Public domain. See "unlicense" statement at the end of this file. 2 | // stb_fft - v0.11 - 2018-12-28 3 | // 4 | // ZhiHan Gao - 200759103@qq.com 5 | // USAGE 6 | // 7 | // This is a single-file library. To use it, do something like the following in one .c file. 8 | // #define STB_FFT_IMPLEMENTAION 9 | // #include "stb_fft.h" 10 | // 11 | // 12 | // You can then #include this file in other parts of the program as you would with any other header file. 13 | // 14 | // The default real type is float. 15 | // To define a macro named USE_DOUBLE_TYPE to change it to double. 16 | // You can read the following function: STB_FFT,STB_IFFT,STB_FFT_R2C,STB_IFFT_C2R for easily usage 17 | // 18 | // 19 | 20 | #ifndef _stb_fft_h_ 21 | #define _stb_fft_h_ 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #ifdef USE_DOUBLE_TYPE 33 | #define stb_real_t double 34 | #else 35 | #define stb_real_t float 36 | #endif 37 | 38 | typedef struct { 39 | stb_real_t real; 40 | stb_real_t imag; 41 | } cmplx; 42 | 43 | typedef struct { 44 | int count; 45 | int* radix; 46 | int* remainder; 47 | int* offsets; 48 | } stb_fft_stages; 49 | 50 | typedef struct { 51 | int N; 52 | cmplx* twiddles; 53 | cmplx* twiddles_ordered; 54 | stb_fft_stages stages; 55 | } stb_fft_plan; 56 | 57 | typedef struct { 58 | stb_fft_plan* half_plan; 59 | cmplx* buffer; 60 | cmplx* twiddles; 61 | } stb_fft_real_plan; 62 | 63 | stb_fft_plan* stb_fft_plan_dft_1d(int N); 64 | 65 | stb_fft_real_plan* stb_fft_real_plan_dft_1d(int N); 66 | 67 | void stb_fft_r2c_exec(stb_fft_real_plan* plan, const stb_real_t* in, cmplx* out); 68 | 69 | void stb_fft_c2r_exec(stb_fft_real_plan* plan, const cmplx* in, stb_real_t* out); 70 | 71 | void stb_fft_exec(const stb_fft_plan* plan, cmplx* in, cmplx* out); 72 | 73 | void stb_ifft_exec(const stb_fft_plan* plan, cmplx* in, cmplx* out); 74 | 75 | // for easily usage 76 | void STB_FFT(cmplx* input, cmplx* output, int n); 77 | 78 | void STB_IFFT(cmplx* input, cmplx* output, int n); 79 | 80 | void STB_FFT_R2C(stb_real_t* input, cmplx* output, int n); 81 | 82 | void STB_IFFT_C2R(cmplx* input, stb_real_t* output, int n); 83 | 84 | #ifdef __cplusplus 85 | } 86 | #endif 87 | #endif 88 | 89 | #ifdef STB_FFT_IMPLEMENTAION 90 | 91 | #ifndef STB_KP5 92 | #define STB_KP5 ((stb_real_t)0.5) 93 | #endif 94 | 95 | #ifndef STB_KP25 96 | #define STB_KP25 ((stb_real_t)0.25) 97 | #endif 98 | 99 | #ifndef STB_KP951056516 100 | #define STB_KP951056516 ((stb_real_t)0.951056516295153572116439333379382143405698634) 101 | #endif 102 | 103 | #ifndef STB_KP587785252 104 | #define STB_KP587785252 ((stb_real_t)0.587785252292473129168705954639072768597652438) 105 | #endif 106 | 107 | #ifndef STB_KP559016994 108 | #define STB_KP559016994 ((stb_real_t)0.559016994374947424102293417182819058860154590) 109 | #endif 110 | 111 | #ifndef STB_KP866025403 112 | #define STB_KP866025403 ((stb_real_t)0.866025403784438646763723170752936183471402627) 113 | #endif 114 | 115 | #ifndef STB_KP900968867 116 | #define STB_KP900968867 ((stb_real_t)0.900968867902419126236102319507445051165919162) 117 | #endif 118 | 119 | #ifndef STB_KP222520933 120 | #define STB_KP222520933 ((stb_real_t)0.222520933956314404288902564496794759466355569) 121 | #endif 122 | 123 | #ifndef STB_KP623489801 124 | #define STB_KP623489801 ((stb_real_t)0.623489801858733530525004884004239810632274731) 125 | #endif 126 | 127 | #ifndef STB_KP781831482 128 | #define STB_KP781831482 ((stb_real_t)0.781831482468029808708444526674057750232334519) 129 | #endif 130 | 131 | #ifndef STB_KP974927912 132 | #define STB_KP974927912 ((stb_real_t)0.974927912181823607018131682993931217232785801) 133 | #endif 134 | 135 | #ifndef STB_KP433883739 136 | #define STB_KP433883739 ((stb_real_t)0.433883739117558120475768332848358754609990728) 137 | #endif 138 | 139 | #ifndef STB_KP707106781 140 | #define STB_KP707106781 ((stb_real_t)0.707106781186547524400844362104849039284835938) 141 | #endif 142 | 143 | #ifndef STB_TWOPI 144 | #define STB_TWOPI ((stb_real_t)6.283185307179586476925286766559005768394338798750211641949889) 145 | #endif 146 | 147 | #ifndef STB_PI 148 | #define STB_PI ((stb_real_t)3.141592653589793238462643383279502884197169399375105820974944) 149 | #endif 150 | 151 | void stbSinCos(double x, stb_real_t* pSin, stb_real_t* pCos) 152 | { 153 | *pSin = (stb_real_t)sin(x); 154 | *pCos = (stb_real_t)cos(x); 155 | } 156 | 157 | void stb_make_twiddles(int n, int count, cmplx* twiddles) 158 | { 159 | double w_pi = STB_TWOPI / n; 160 | double t = 0; 161 | for (int i = 0; i < count; ++i) { 162 | stbSinCos(t, &twiddles[i].imag, &twiddles[i].real); 163 | t += w_pi; 164 | } 165 | }; 166 | 167 | int stb_make_twiddles_sequential(int n, cmplx* twiddles, stb_fft_stages* stages) 168 | { 169 | int size = 0; 170 | { 171 | int offset = 0; 172 | for (int s = 0; s < stages->count; s++) { 173 | int r = stages->radix[s]; 174 | int count = stages->remainder[s]; 175 | int amount = (r <= 8) ? (r - 1) * (count - 1) : 0; 176 | stages->offsets[s] = amount; 177 | offset += amount; 178 | } 179 | size = offset; 180 | for (int s = 0; s < stages->count; s++) { 181 | int count = stages->offsets[s]; 182 | offset -= count; 183 | stages->offsets[s] = offset; 184 | } 185 | } 186 | if (twiddles) { 187 | int w = 1; 188 | for (int s = 0; s < stages->count; s++) { 189 | double w_pi = STB_TWOPI * w / n; 190 | const int r = stages->radix[s]; 191 | const int count = stages->remainder[s]; 192 | int offset = stages->offsets[s]; 193 | if (r <= 8) { 194 | for (int i = 1; i < count; i++) { 195 | for (int j = 1; j < r; j++) { 196 | stbSinCos(w_pi * i * j, &twiddles[offset].imag, &twiddles[offset].real); 197 | offset++; 198 | } 199 | } 200 | } 201 | w *= r; 202 | } 203 | } 204 | return size; 205 | }; 206 | 207 | typedef struct { 208 | int calc_twiddles; 209 | int stage_count; 210 | int twiddles_size; 211 | } stb_stage_info; 212 | 213 | stb_stage_info stb_calculate_stages(int n, stb_fft_plan* plan) 214 | { 215 | int calc_twiddles = 0; 216 | int stage = 0; 217 | int twiddles_size = 0; 218 | while (n > 1) { 219 | int i = 8; 220 | for (; i > 1; i--) { 221 | if (!(n % i)) { 222 | twiddles_size += ((i - 1) * (n - 1)); 223 | break; 224 | } 225 | } 226 | if (i == 1) { 227 | calc_twiddles = 1; 228 | i = 7; 229 | for (; i <= n; i++) { 230 | if (!(n % i)) { 231 | break; 232 | } 233 | } 234 | } 235 | n /= i; 236 | if (plan) { 237 | plan->stages.radix[stage] = i; 238 | plan->stages.remainder[stage] = n; 239 | } 240 | stage++; 241 | } 242 | stb_stage_info result = { 243 | calc_twiddles, stage, twiddles_size 244 | }; 245 | return result; 246 | } 247 | 248 | int stb_make_fft_plan(int N, stb_fft_plan* plan) 249 | { 250 | if (N == 0) 251 | return 0; 252 | stb_stage_info info = stb_calculate_stages(N, NULL); 253 | const int size_plan = sizeof(stb_fft_plan); 254 | const int size_radix = info.stage_count * sizeof(int); 255 | const int size_remainder = info.stage_count * sizeof(int); 256 | const int size_offsets = info.stage_count * sizeof(int); 257 | const int twiddles_ordered_size = info.twiddles_size * sizeof(cmplx); 258 | const int twiddles_size = N * sizeof(cmplx) * info.calc_twiddles; 259 | const int total_size = size_plan 260 | + twiddles_size 261 | + size_radix + size_remainder + size_offsets + twiddles_ordered_size; 262 | if (plan) { 263 | uint8_t* data = (uint8_t*)(plan); 264 | uint8_t* data_twiddles = data + size_plan; 265 | uint8_t* data_radix = data_twiddles + twiddles_size; 266 | uint8_t* data_remainder = data_radix + size_radix; 267 | uint8_t* data_offsets = data_remainder + size_offsets; 268 | uint8_t* data_twiddles_ordered = data_offsets + size_remainder; 269 | plan->twiddles = (info.calc_twiddles) ? (cmplx*)(data_twiddles) : NULL; 270 | plan->stages.radix = (int*)(data_radix); 271 | plan->stages.remainder = (int*)(data_remainder); 272 | plan->stages.offsets = (int*)(data_offsets); 273 | plan->stages.count = info.stage_count; 274 | plan->twiddles_ordered = (cmplx*)(data_twiddles_ordered); 275 | plan->N = N; 276 | if (plan->twiddles) { 277 | stb_make_twiddles(N, N, plan->twiddles); 278 | } 279 | stb_calculate_stages(N, plan); 280 | stb_make_twiddles_sequential(N, plan->twiddles_ordered, &plan->stages); 281 | } 282 | return total_size; 283 | } 284 | 285 | stb_fft_plan* stb_fft_plan_dft_1d(int N) 286 | { 287 | if (N == 0) 288 | return 0; 289 | stb_stage_info info = stb_calculate_stages(N, NULL); 290 | const int size_plan = sizeof(stb_fft_plan); 291 | const int size_radix = info.stage_count * sizeof(int); 292 | const int size_remainder = info.stage_count * sizeof(int); 293 | const int size_offsets = info.stage_count * sizeof(int); 294 | const int twiddles_ordered_size = info.twiddles_size * sizeof(cmplx); 295 | const int twiddles_size = N * sizeof(cmplx) * info.calc_twiddles; 296 | const int total_size = size_plan 297 | + twiddles_size 298 | + size_radix + size_remainder + size_offsets + twiddles_ordered_size; 299 | stb_fft_plan* plan = (stb_fft_plan*)calloc(total_size, 1); 300 | if (plan) { 301 | uint8_t* data = (uint8_t*)(plan); 302 | uint8_t* data_twiddles = data + size_plan; 303 | uint8_t* data_radix = data_twiddles + twiddles_size; 304 | uint8_t* data_remainder = data_radix + size_radix; 305 | uint8_t* data_offsets = data_remainder + size_offsets; 306 | uint8_t* data_twiddles_ordered = data_offsets + size_remainder; 307 | plan->twiddles = (info.calc_twiddles) ? (cmplx*)(data_twiddles) : NULL; 308 | plan->stages.radix = (int*)(data_radix); 309 | plan->stages.remainder = (int*)(data_remainder); 310 | plan->stages.offsets = (int*)(data_offsets); 311 | plan->stages.count = info.stage_count; 312 | plan->twiddles_ordered = (cmplx*)(data_twiddles_ordered); 313 | plan->N = N; 314 | if (plan->twiddles) { 315 | stb_make_twiddles(N, N, plan->twiddles); 316 | } 317 | stb_calculate_stages(N, plan); 318 | stb_make_twiddles_sequential(N, plan->twiddles_ordered, &plan->stages); 319 | } 320 | return plan; 321 | } 322 | 323 | stb_fft_real_plan* stb_fft_real_plan_dft_1d(int N) 324 | { 325 | if (N == 0) 326 | return 0; 327 | if (N & 1) { 328 | fprintf(stderr, "Real FFT must be even.\n"); 329 | return 0; 330 | } 331 | N >>= 1; 332 | int c_plan_size = stb_make_fft_plan(N, NULL); 333 | int mem_needed = sizeof(stb_fft_real_plan) + c_plan_size + sizeof(cmplx) * (N * 3 / 2); 334 | stb_fft_real_plan* plan = (stb_fft_real_plan*)calloc(mem_needed, 1); 335 | if (plan) { 336 | plan->half_plan = (stb_fft_plan*)(plan + 1); 337 | plan->buffer = (cmplx*)(((char*)plan->half_plan) + c_plan_size); 338 | plan->twiddles = plan->buffer + N; 339 | stb_make_fft_plan(N, plan->half_plan); 340 | for (int i = 0; i < N / 2; ++i) { 341 | stbSinCos(-STB_PI * ((double)(i + 1) / N + 0.5), &plan->twiddles[i].imag, &plan->twiddles[i].real); 342 | } 343 | } 344 | return plan; 345 | } 346 | 347 | void stb_general_dit(cmplx* twiddles, cmplx* out, int count, 348 | int cur_sign, int radix, int N, int reverse) 349 | { 350 | cmplx* scratch = (cmplx*)calloc(radix, sizeof(cmplx)); 351 | if (scratch == 0) 352 | return; 353 | if (reverse) { 354 | for (int butterfly = 0; butterfly < count; ++butterfly) { 355 | int idx = butterfly; 356 | for (int r = 0; r < radix; ++r) { 357 | scratch[r] = out[idx]; 358 | idx += count; 359 | } 360 | idx = butterfly; 361 | for (int r = 0; r < radix; ++r) { 362 | int tw_idx = 0; 363 | out[idx] = *scratch; 364 | for (int cr = 1; cr < radix; ++cr) { 365 | tw_idx += cur_sign * idx; 366 | if (tw_idx >= N) 367 | tw_idx -= N; 368 | out[idx].real += twiddles[tw_idx].real * scratch[cr].real 369 | - twiddles[tw_idx].imag * scratch[cr].imag; 370 | out[idx].imag += twiddles[tw_idx].real * scratch[cr].imag 371 | + scratch[cr].real * twiddles[tw_idx].imag; 372 | } 373 | idx += count; 374 | } 375 | } 376 | } else { 377 | for (int butterfly = 0; butterfly < count; ++butterfly) { 378 | int idx = butterfly; 379 | for (int r = 0; r < radix; ++r) { 380 | scratch[r] = out[idx]; 381 | idx += count; 382 | } 383 | idx = butterfly; 384 | for (int r = 0; r < radix; ++r) { 385 | int tw_idx = 0; 386 | out[idx] = *scratch; 387 | for (int cr = 1; cr < radix; ++cr) { 388 | tw_idx += cur_sign * idx; 389 | if (tw_idx >= N) 390 | tw_idx -= N; 391 | out[idx].real += twiddles[tw_idx].real * scratch[cr].real 392 | + twiddles[tw_idx].imag * scratch[cr].imag; 393 | out[idx].imag += twiddles[tw_idx].real * scratch[cr].imag 394 | - scratch[cr].real * twiddles[tw_idx].imag; 395 | } 396 | idx += count; 397 | } 398 | } 399 | } 400 | free(scratch); 401 | } 402 | 403 | void stb_radix_2_dit(const cmplx* tw, cmplx* out, int count) 404 | { 405 | int m; 406 | cmplx* output; 407 | stb_real_t T1 = out[0].real; 408 | stb_real_t T2 = out[count].real; 409 | out[count].real = out[0].real - T2; 410 | out[0].real = T1 + T2; 411 | stb_real_t T3 = out[0].imag; 412 | stb_real_t T4 = out[count].imag; 413 | out[count].imag = T3 - T4; 414 | out[0].imag = T3 + T4; 415 | output = out + 1; 416 | m = 1; 417 | while (m < count) { 418 | stb_real_t T1_0 = output[0].real; 419 | stb_real_t T8 = output[0].imag; 420 | stb_real_t T3_0 = output[count].real; 421 | stb_real_t T5 = output[count].imag; 422 | stb_real_t T4_0 = tw[0].imag; 423 | stb_real_t T6 = T4_0 * T5 + tw[0].real * T3_0; 424 | stb_real_t T7 = tw[0].real * T5 - T4_0 * T3_0; 425 | output[count].real = output[0].real - T6; 426 | output[count].imag = T8 - T7; 427 | output[0].real = T1_0 + T6; 428 | output[0].imag = T7 + T8; 429 | ++m; 430 | ++output; 431 | ++tw; 432 | } 433 | } 434 | 435 | void stb_radix_3_dit(const cmplx* tw, cmplx* out, int count) 436 | { 437 | int m; 438 | cmplx* output; 439 | stb_real_t T1 = out[0].real; 440 | stb_real_t T10 = out[0].imag; 441 | stb_real_t T2 = out[count].real; 442 | stb_real_t T3 = out[2 * count].real; 443 | stb_real_t T9 = (T3 - T2) * STB_KP866025403; 444 | stb_real_t T6 = out[count].imag; 445 | stb_real_t T7 = out[2 * count].imag; 446 | stb_real_t T8 = (T6 - T7) * STB_KP866025403; 447 | out[0].real = out[0].real + T2 + T3; 448 | out[0].imag = T10 + T6 + T7; 449 | stb_real_t T5 = T1 - STB_KP5 * (T2 + T3); 450 | out[2 * count].real = T5 - T8; 451 | out[count].real = T5 + T8; 452 | stb_real_t T12 = T10 - STB_KP5 * (T6 + T7); 453 | out[count].imag = T9 + T12; 454 | out[2 * count].imag = T12 - T9; 455 | output = out + 1; 456 | m = 1; 457 | while (m < count) { 458 | stb_real_t T1_0 = output[0].real; 459 | stb_real_t T18 = output[0].imag; 460 | stb_real_t T3_0 = output[count].real; 461 | stb_real_t T5_0 = output[count].imag; 462 | stb_real_t T4_0 = tw[0].imag; 463 | stb_real_t T6_0 = T4_0 * T5_0 + tw[0].real * T3_0; 464 | stb_real_t T14 = tw[0].real * T5_0 - T4_0 * T3_0; 465 | stb_real_t T8_0 = output[2 * count].real; 466 | stb_real_t T10_0 = output[2 * count].imag; 467 | stb_real_t T7_0 = tw[1].real; 468 | stb_real_t T9_0 = tw[1].imag; 469 | stb_real_t T11_0 = T9_0 * T10_0 + T7_0 * T8_0; 470 | stb_real_t T15 = T7_0 * T10_0 - T9_0 * T8_0; 471 | stb_real_t T12_0 = T6_0 + T11_0; 472 | stb_real_t T17 = T14 + T15; 473 | output[0].real = output[0].real + T12_0; 474 | output[0].imag = T17 + T18; 475 | stb_real_t T16 = (T14 - T15) * STB_KP866025403; 476 | output[2 * count].real = T1_0 - STB_KP5 * T12_0 - T16; 477 | output[count].real = T1_0 - STB_KP5 * T12_0 + T16; 478 | stb_real_t T20 = T18 - STB_KP5 * T17; 479 | output[count].imag = (T11_0 - T6_0) * STB_KP866025403 + T20; 480 | output[2 * count].imag = T20 - (T11_0 - T6_0) * STB_KP866025403; 481 | ++m; 482 | ++output; 483 | tw += 2; 484 | } 485 | } 486 | 487 | void stb_radix_4_dit(const cmplx* tw, cmplx* out, int count) 488 | { 489 | int m; 490 | cmplx* output; 491 | stb_real_t T2 = out[2 * count].real; 492 | stb_real_t T3 = out[0].real + T2; 493 | stb_real_t T11 = out[0].real - T2; 494 | stb_real_t T7 = out[0].imag; 495 | stb_real_t T8 = out[2 * count].imag; 496 | stb_real_t T4 = out[count].real; 497 | stb_real_t T5 = out[3 * count].real; 498 | stb_real_t T12 = out[count].imag; 499 | stb_real_t T13 = out[3 * count].imag; 500 | out[2 * count].real = T3 - (T4 + T5); 501 | out[2 * count].imag = T7 + T8 - (T12 + T13); 502 | out[0].real = T3 + T4 + T5; 503 | out[0].imag = T7 + T8 + T12 + T13; 504 | out[count].imag = T7 - T8 - (T4 - T5); 505 | out[count].real = T11 + T12 - T13; 506 | out[3 * count].imag = T4 - T5 + T7 - T8; 507 | out[3 * count].real = T11 - (T12 - T13); 508 | output = out + 1; 509 | m = 1; 510 | while (m < count) { 511 | stb_real_t T1_0 = output[0].real; 512 | stb_real_t T25 = output[0].imag; 513 | stb_real_t T3_0 = output[2 * count].real; 514 | stb_real_t T5_0 = output[2 * count].imag; 515 | stb_real_t T2_0 = tw[1].real; 516 | stb_real_t T4_0 = tw[1].imag; 517 | stb_real_t T6_0 = T4_0 * T5_0 + T2_0 * T3_0; 518 | stb_real_t T24 = T2_0 * T5_0 - T4_0 * T3_0; 519 | stb_real_t T9_0 = output[count].real; 520 | stb_real_t T11_0 = output[count].imag; 521 | stb_real_t T10_0 = tw[0].imag; 522 | stb_real_t T12_0 = T10_0 * T11_0 + tw[0].real * T9_0; 523 | stb_real_t T20 = tw[0].real * T11_0 - T10_0 * T9_0; 524 | stb_real_t T14_0 = output[3 * count].real; 525 | stb_real_t T16_0 = output[3 * count].imag; 526 | stb_real_t T13_0 = tw[2].real; 527 | stb_real_t T15_0 = tw[2].imag; 528 | stb_real_t T17 = T15_0 * T16_0 + T13_0 * T14_0; 529 | stb_real_t T21 = T13_0 * T16_0 - T15_0 * T14_0; 530 | stb_real_t T18 = T12_0 + T17; 531 | output[2 * count].real = output[0].real + T6_0 - T18; 532 | output[0].real = T1_0 + T6_0 + T18; 533 | output[0].imag = T20 + T21 + T24 + T25; 534 | output[2 * count].imag = T24 + T25 - (T20 + T21); 535 | output[3 * count].real = T1_0 - T6_0 - (T20 - T21); 536 | output[count].real = T1_0 - T6_0 + T20 - T21; 537 | output[count].imag = T25 - T24 - (T12_0 - T17); 538 | output[3 * count].imag = T12_0 - T17 + T25 - T24; 539 | ++m; 540 | ++output; 541 | tw += 3; 542 | } 543 | } 544 | 545 | void stb_radix_5_dit(const cmplx* tw, cmplx* out, int count) 546 | { 547 | int m; 548 | cmplx* output; 549 | stb_real_t T1 = out[0].real; 550 | stb_real_t T24 = out[0].imag; 551 | stb_real_t T2 = out[count].real; 552 | stb_real_t T3 = out[4 * count].real; 553 | stb_real_t T5 = out[2 * count].real; 554 | stb_real_t T6 = out[3 * count].real; 555 | stb_real_t T8 = T2 + T3 + T5 + T6; 556 | stb_real_t T9 = (T2 + T3 - (T5 + T6)) * STB_KP559016994; 557 | stb_real_t T12 = out[count].imag; 558 | stb_real_t T13 = out[4 * count].imag; 559 | stb_real_t T15 = out[2 * count].imag; 560 | stb_real_t T16 = out[3 * count].imag; 561 | stb_real_t T25 = T12 + T13 + T15 + T16; 562 | stb_real_t T23 = (T12 + T13 - (T15 + T16)) * STB_KP559016994; 563 | out[0].real = out[0].real + T8; 564 | out[0].imag = T24 + T25; 565 | stb_real_t T18 = STB_KP587785252 * (T15 - T16) + STB_KP951056516 * (T12 - T13); 566 | stb_real_t T20 = STB_KP951056516 * (T15 - T16) - STB_KP587785252 * (T12 - T13); 567 | stb_real_t T11 = T9 + T1 - STB_KP25 * T8; 568 | stb_real_t T19 = T1 - STB_KP25 * T8 - T9; 569 | out[4 * count].real = T11 - T18; 570 | out[3 * count].real = T19 + T20; 571 | out[count].real = T11 + T18; 572 | out[2 * count].real = T19 - T20; 573 | stb_real_t T30 = STB_KP587785252 * (T5 - T6) + STB_KP951056516 * (T2 - T3); 574 | stb_real_t T31 = STB_KP951056516 * (T5 - T6) - STB_KP587785252 * (T2 - T3); 575 | stb_real_t T27 = T23 + T24 - STB_KP25 * T25; 576 | stb_real_t T32 = T24 - STB_KP25 * T25 - T23; 577 | out[count].imag = T27 - T30; 578 | out[3 * count].imag = T32 - T31; 579 | out[4 * count].imag = T30 + T27; 580 | out[2 * count].imag = T31 + T32; 581 | output = out + 1; 582 | m = 1; 583 | while (m < count) { 584 | stb_real_t T1_0 = output[0].real; 585 | stb_real_t T40 = output[0].imag; 586 | stb_real_t T3_0 = output[count].real; 587 | stb_real_t T5_0 = output[count].imag; 588 | stb_real_t T4_0 = tw[0].imag; 589 | stb_real_t T19_0 = output[3 * count].real; 590 | stb_real_t T21_0 = output[3 * count].imag; 591 | stb_real_t T18_0 = tw[2].real; 592 | stb_real_t T20_0 = tw[2].imag; 593 | stb_real_t T22_0 = T20_0 * T21_0 + T18_0 * T19_0; 594 | stb_real_t T32_0 = T18_0 * T21_0 - T20_0 * T19_0; 595 | stb_real_t T8_0 = output[4 * count].real; 596 | stb_real_t T10_0 = output[4 * count].imag; 597 | stb_real_t T7_0 = tw[3].real; 598 | stb_real_t T9_0 = tw[3].imag; 599 | stb_real_t T11_0 = T9_0 * T10_0 + T7_0 * T8_0; 600 | stb_real_t T29_0 = T7_0 * T10_0 - T9_0 * T8_0; 601 | stb_real_t T14_0 = output[2 * count].real; 602 | stb_real_t T16_0 = output[2 * count].imag; 603 | stb_real_t T13_0 = tw[1].real; 604 | stb_real_t T15_0 = tw[1].imag; 605 | stb_real_t T30_0 = tw[0].real * T5_0 - T4_0 * T3_0 - T29_0; 606 | stb_real_t T33 = T13_0 * T16_0 - T15_0 * T14_0 - T32_0; 607 | stb_real_t T45 = T15_0 * T16_0 + T13_0 * T14_0 - T22_0; 608 | stb_real_t T44 = T4_0 * T5_0 + tw[0].real * T3_0 - T11_0; 609 | stb_real_t T37 = tw[0].real * T5_0 - T4_0 * T3_0 + T29_0; 610 | stb_real_t T38 = T13_0 * T16_0 - T15_0 * T14_0 + T32_0; 611 | stb_real_t T39 = T37 + T38; 612 | stb_real_t T12_0 = T4_0 * T5_0 + tw[0].real * T3_0 + T11_0; 613 | stb_real_t T23_0 = T15_0 * T16_0 + T13_0 * T14_0 + T22_0; 614 | stb_real_t T24_0 = T12_0 + T23_0; 615 | output[0].real = output[0].real + T24_0; 616 | output[0].imag = T39 + T40; 617 | stb_real_t T34 = STB_KP587785252 * T33 + STB_KP951056516 * T30_0; 618 | stb_real_t T36 = STB_KP951056516 * T33 - STB_KP587785252 * T30_0; 619 | stb_real_t T27_0 = (T12_0 - T23_0) * STB_KP559016994 + T1_0 - STB_KP25 * T24_0; 620 | stb_real_t T35 = T1_0 - STB_KP25 * T24_0 - (T12_0 - T23_0) * STB_KP559016994; 621 | output[4 * count].real = T27_0 - T34; 622 | output[3 * count].real = T35 + T36; 623 | output[count].real = T27_0 + T34; 624 | output[2 * count].real = T35 - T36; 625 | stb_real_t T46 = STB_KP587785252 * T45 + STB_KP951056516 * T44; 626 | stb_real_t T47 = STB_KP951056516 * T45 - STB_KP587785252 * T44; 627 | stb_real_t T43 = (T37 - T38) * STB_KP559016994 + T40 - STB_KP25 * T39; 628 | stb_real_t T48 = T40 - STB_KP25 * T39 - (T37 - T38) * STB_KP559016994; 629 | output[count].imag = T43 - T46; 630 | output[3 * count].imag = T48 - T47; 631 | output[4 * count].imag = T46 + T43; 632 | output[2 * count].imag = T47 + T48; 633 | ++m; 634 | ++output; 635 | tw += 4; 636 | } 637 | } 638 | 639 | void stb_radix_6_dit(const cmplx* tw, cmplx* out, int count) 640 | { 641 | int m; 642 | cmplx* output; 643 | stb_real_t T2 = out[3 * count].real; 644 | stb_real_t T3 = out[0].real - T2; 645 | stb_real_t T11 = out[0].real + T2; 646 | stb_real_t T24 = out[0].imag; 647 | stb_real_t T25 = out[3 * count].imag; 648 | stb_real_t T4 = out[2 * count].real; 649 | stb_real_t T5 = out[5 * count].real; 650 | stb_real_t T7 = out[4 * count].real; 651 | stb_real_t T8 = out[count].real; 652 | stb_real_t T10 = T4 - T5 + T7 - T8; 653 | stb_real_t T14 = T4 + T5 + T7 + T8; 654 | stb_real_t T16 = out[2 * count].imag; 655 | stb_real_t T17 = out[5 * count].imag; 656 | stb_real_t T19 = out[4 * count].imag; 657 | stb_real_t T20 = out[count].imag; 658 | stb_real_t T27 = T16 - T17 + T19 - T20; 659 | stb_real_t T34 = T16 + T17 + T19 + T20; 660 | out[3 * count].real = T3 + T10; 661 | out[3 * count].imag = T24 - T25 + T27; 662 | out[0].real = T11 + T14; 663 | out[0].imag = T24 + T25 + T34; 664 | stb_real_t T22 = (T16 - T17 - (T19 - T20)) * STB_KP866025403; 665 | out[5 * count].real = T3 - STB_KP5 * T10 - T22; 666 | out[count].real = T3 - STB_KP5 * T10 + T22; 667 | stb_real_t T23 = (T7 - T8 - (T4 - T5)) * STB_KP866025403; 668 | stb_real_t T28 = T24 - T25 - STB_KP5 * T27; 669 | out[count].imag = T23 + T28; 670 | out[5 * count].imag = T28 - T23; 671 | stb_real_t T32 = (T16 + T17 - (T19 + T20)) * STB_KP866025403; 672 | out[2 * count].real = T11 - STB_KP5 * T14 - T32; 673 | out[4 * count].real = T11 - STB_KP5 * T14 + T32; 674 | stb_real_t T35 = T24 + T25 - STB_KP5 * T34; 675 | stb_real_t T36 = (T7 + T8 - (T4 + T5)) * STB_KP866025403; 676 | out[2 * count].imag = T35 - T36; 677 | out[4 * count].imag = T36 + T35; 678 | output = out + 1; 679 | m = 1; 680 | while (m < count) { 681 | stb_real_t T49 = output[0].imag; 682 | stb_real_t T3_0 = output[3 * count].real; 683 | stb_real_t T5_0 = output[3 * count].imag; 684 | stb_real_t T2_0 = tw[2].real; 685 | stb_real_t T4_0 = tw[2].imag; 686 | stb_real_t T6_0 = T4_0 * T5_0 + T2_0 * T3_0; 687 | stb_real_t T54 = T49 - (T2_0 * T5_0 - T4_0 * T3_0); 688 | stb_real_t T31_0 = output[0].real + T6_0; 689 | stb_real_t T50 = T2_0 * T5_0 - T4_0 * T3_0 + T49; 690 | stb_real_t T20_0 = output[4 * count].real; 691 | stb_real_t T22_0 = output[4 * count].imag; 692 | stb_real_t T19_0 = tw[3].real; 693 | stb_real_t T21_0 = tw[3].imag; 694 | stb_real_t T25_0 = output[count].real; 695 | stb_real_t T27_0 = output[count].imag; 696 | stb_real_t T26_0 = tw[0].imag; 697 | stb_real_t T28_0 = T26_0 * T27_0 + tw[0].real * T25_0; 698 | stb_real_t T40 = tw[0].real * T27_0 - T26_0 * T25_0; 699 | stb_real_t T29_0 = T21_0 * T22_0 + T19_0 * T20_0 - T28_0; 700 | stb_real_t T45 = T19_0 * T22_0 - T21_0 * T20_0 + T40; 701 | stb_real_t T33_0 = T21_0 * T22_0 + T19_0 * T20_0 + T28_0; 702 | stb_real_t T41 = T19_0 * T22_0 - T21_0 * T20_0 - T40; 703 | stb_real_t T9_0 = output[2 * count].real; 704 | stb_real_t T11_0 = output[2 * count].imag; 705 | stb_real_t T8_0 = tw[1].real; 706 | stb_real_t T10_0 = tw[1].imag; 707 | stb_real_t T14_0 = output[5 * count].real; 708 | stb_real_t T16_0 = output[5 * count].imag; 709 | stb_real_t T13_0 = tw[4].real; 710 | stb_real_t T15_0 = tw[4].imag; 711 | stb_real_t T17_0 = T15_0 * T16_0 + T13_0 * T14_0; 712 | stb_real_t T37 = T13_0 * T16_0 - T15_0 * T14_0; 713 | stb_real_t T44 = T8_0 * T11_0 - T10_0 * T9_0 + T37; 714 | stb_real_t T32_0 = T10_0 * T11_0 + T8_0 * T9_0 + T17_0; 715 | stb_real_t T42 = (T8_0 * T11_0 - T10_0 * T9_0 - T37 - T41) * STB_KP866025403; 716 | stb_real_t T30_0 = T10_0 * T11_0 + T8_0 * T9_0 - T17_0 + T29_0; 717 | stb_real_t T35_0 = output[0].real - T6_0 - STB_KP5 * T30_0; 718 | output[3 * count].real = output[0].real - T6_0 + T30_0; 719 | output[count].real = T35_0 + T42; 720 | output[5 * count].real = T35_0 - T42; 721 | stb_real_t T53 = (T29_0 - (T10_0 * T11_0 + T8_0 * T9_0 - T17_0)) * STB_KP866025403; 722 | stb_real_t T55 = T8_0 * T11_0 - T10_0 * T9_0 - T37 + T41; 723 | stb_real_t T56 = T54 - STB_KP5 * T55; 724 | output[count].imag = T53 + T56; 725 | output[3 * count].imag = T55 + T54; 726 | output[5 * count].imag = T56 - T53; 727 | stb_real_t T46 = (T44 - T45) * STB_KP866025403; 728 | stb_real_t T43 = T31_0 - STB_KP5 * (T32_0 + T33_0); 729 | output[0].real = T31_0 + T32_0 + T33_0; 730 | output[4 * count].real = T43 + T46; 731 | output[2 * count].real = T43 - T46; 732 | stb_real_t T52 = (T33_0 - T32_0) * STB_KP866025403; 733 | stb_real_t T51 = T50 - STB_KP5 * (T44 + T45); 734 | output[0].imag = T44 + T45 + T50; 735 | output[4 * count].imag = T52 + T51; 736 | output[2 * count].imag = T51 - T52; 737 | ++m; 738 | ++output; 739 | tw += 5; 740 | } 741 | } 742 | 743 | void stb_radix_7_dit(const cmplx* tw, cmplx* out, int count) 744 | { 745 | int m; 746 | cmplx* output; 747 | stb_real_t T1 = out[0].real; 748 | stb_real_t T30 = out[0].imag; 749 | stb_real_t T2 = out[count].real; 750 | stb_real_t T3 = out[6 * count].real; 751 | stb_real_t T12 = out[count].imag; 752 | stb_real_t T13 = out[6 * count].imag; 753 | stb_real_t T5 = out[2 * count].real; 754 | stb_real_t T6 = out[5 * count].real; 755 | stb_real_t T18 = out[2 * count].imag; 756 | stb_real_t T19 = out[5 * count].imag; 757 | stb_real_t T8 = out[3 * count].real; 758 | stb_real_t T9 = out[4 * count].real; 759 | stb_real_t T15 = out[3 * count].imag; 760 | stb_real_t T16 = out[4 * count].imag; 761 | out[0].real = out[0].real + T2 + T3 + T5 + T6 + T8 + T9; 762 | out[0].imag = T30 + T12 + T13 + T18 + T19 + T15 + T16; 763 | stb_real_t T21 = STB_KP974927912 * (T12 - T13) - STB_KP781831482 * (T15 - T16) - STB_KP433883739 * (T18 - T19); 764 | out[5 * count].real = STB_KP623489801 * (T8 + T9) 765 | + T1 766 | - (STB_KP222520933 * (T2 + T3) 767 | + STB_KP900968867 * (T5 + T6)) 768 | - T21; 769 | out[2 * count].real = STB_KP623489801 * (T8 + T9) 770 | + T1 771 | - (STB_KP222520933 * (T2 + T3) 772 | + STB_KP900968867 * (T5 + T6)) 773 | + T21; 774 | stb_real_t T38 = STB_KP623489801 * (T15 + T16) + T30 - (STB_KP222520933 * (T12 + T13) + STB_KP900968867 * (T18 + T19)); 775 | out[2 * count].imag = STB_KP974927912 * (T3 - T2) 776 | - STB_KP781831482 * (T9 - T8) 777 | - STB_KP433883739 * (T6 - T5) 778 | + T38; 779 | out[5 * count].imag = T38 780 | - (STB_KP974927912 * (T3 - T2) 781 | - STB_KP781831482 * (T9 - T8) 782 | - STB_KP433883739 * (T6 - T5)); 783 | stb_real_t T23 = STB_KP433883739 * (T15 - T16) + STB_KP781831482 * (T12 - T13) + STB_KP974927912 * (T18 - T19); 784 | out[6 * count].real = STB_KP623489801 * (T2 + T3) 785 | + T1 786 | - (STB_KP222520933 * (T5 + T6) 787 | + STB_KP900968867 * (T8 + T9)) 788 | - T23; 789 | out[count].real = STB_KP623489801 * (T2 + T3) 790 | + T1 791 | - (STB_KP222520933 * (T5 + T6) 792 | + STB_KP900968867 * (T8 + T9)) 793 | + T23; 794 | stb_real_t T36 = STB_KP623489801 * (T12 + T13) + T30 - (STB_KP222520933 * (T18 + T19) + STB_KP900968867 * (T15 + T16)); 795 | out[count].imag = STB_KP433883739 * (T9 - T8) 796 | + STB_KP781831482 * (T3 - T2) 797 | + STB_KP974927912 * (T6 - T5) 798 | + T36; 799 | out[6 * count].imag = T36 800 | - (STB_KP433883739 * (T9 - T8) 801 | + STB_KP781831482 * (T3 - T2) 802 | + STB_KP974927912 * (T6 - T5)); 803 | stb_real_t T25 = STB_KP974927912 * (T15 - T16) + STB_KP433883739 * (T12 - T13) - STB_KP781831482 * (T18 - T19); 804 | stb_real_t T24 = STB_KP623489801 * (T5 + T6) + T1 - (STB_KP900968867 * (T2 + T3) + STB_KP222520933 * (T8 + T9)); 805 | out[4 * count].real = T24 - T25; 806 | out[3 * count].real = T24 + T25; 807 | stb_real_t T29 = STB_KP974927912 * (T9 - T8) + STB_KP433883739 * (T3 - T2) - STB_KP781831482 * (T6 - T5); 808 | stb_real_t T34 = STB_KP623489801 * (T18 + T19) + T30 - (STB_KP900968867 * (T12 + T13) + STB_KP222520933 * (T15 + T16)); 809 | out[3 * count].imag = T29 + T34; 810 | out[4 * count].imag = T34 - T29; 811 | output = out + 1; 812 | m = 1; 813 | while (m < count) { 814 | stb_real_t T1_0 = output[0].real; 815 | stb_real_t T53 = output[0].imag; 816 | stb_real_t T3_0 = output[count].real; 817 | stb_real_t T5_0 = output[count].imag; 818 | stb_real_t T4_0 = tw[0].imag; 819 | stb_real_t T8_0 = output[6 * count].real; 820 | stb_real_t T10_0 = output[6 * count].imag; 821 | stb_real_t T7_0 = tw[5].real; 822 | stb_real_t T9_0 = tw[5].imag; 823 | stb_real_t T37_0 = T7_0 * T10_0 - T9_0 * T8_0; 824 | stb_real_t T12_0 = T4_0 * T5_0 + tw[0].real * T3_0 + T9_0 * T10_0 + T7_0 * T8_0; 825 | stb_real_t T54 = T9_0 * T10_0 + T7_0 * T8_0 - (T4_0 * T5_0 + tw[0].real * T3_0); 826 | stb_real_t T38_0 = tw[0].real * T5_0 - T4_0 * T3_0 - T37_0; 827 | stb_real_t T50 = tw[0].real * T5_0 - T4_0 * T3_0 + T37_0; 828 | stb_real_t T14_0 = output[2 * count].real; 829 | stb_real_t T16_0 = output[2 * count].imag; 830 | stb_real_t T13_0 = tw[1].real; 831 | stb_real_t T15_0 = tw[1].imag; 832 | stb_real_t T19_0 = output[5 * count].real; 833 | stb_real_t T21_0 = output[5 * count].imag; 834 | stb_real_t T18_0 = tw[4].real; 835 | stb_real_t T20_0 = tw[4].imag; 836 | stb_real_t T43 = T18_0 * T21_0 - T20_0 * T19_0; 837 | stb_real_t T23_0 = T15_0 * T16_0 + T13_0 * T14_0 + T20_0 * T21_0 + T18_0 * T19_0; 838 | stb_real_t T55 = T20_0 * T21_0 + T18_0 * T19_0 - (T15_0 * T16_0 + T13_0 * T14_0); 839 | stb_real_t T44 = T13_0 * T16_0 - T15_0 * T14_0 - T43; 840 | stb_real_t T51 = T13_0 * T16_0 - T15_0 * T14_0 + T43; 841 | stb_real_t T25_0 = output[3 * count].real; 842 | stb_real_t T27_0 = output[3 * count].imag; 843 | stb_real_t T24_0 = tw[2].real; 844 | stb_real_t T26_0 = tw[2].imag; 845 | stb_real_t T30_0 = output[4 * count].real; 846 | stb_real_t T32_0 = output[4 * count].imag; 847 | stb_real_t T29_0 = tw[3].real; 848 | stb_real_t T31_0 = tw[3].imag; 849 | stb_real_t T40 = T29_0 * T32_0 - T31_0 * T30_0; 850 | stb_real_t T34_0 = T26_0 * T27_0 + T24_0 * T25_0 + T31_0 * T32_0 + T29_0 * T30_0; 851 | stb_real_t T56 = T31_0 * T32_0 + T29_0 * T30_0 - (T26_0 * T27_0 + T24_0 * T25_0); 852 | stb_real_t T41 = T24_0 * T27_0 - T26_0 * T25_0 - T40; 853 | stb_real_t T52 = T24_0 * T27_0 - T26_0 * T25_0 + T40; 854 | output[0].real = output[0].real + T12_0 + T23_0 + T34_0; 855 | output[0].imag = T50 + T51 + T52 + T53; 856 | stb_real_t T45 = STB_KP974927912 * T38_0 - STB_KP781831482 * T41 - STB_KP433883739 * T44; 857 | output[5 * count].real = STB_KP623489801 * T34_0 858 | + T1_0 859 | - (STB_KP222520933 * T12_0 860 | + STB_KP900968867 * T23_0) 861 | - T45; 862 | output[2 * count].real = STB_KP623489801 * T34_0 863 | + T1_0 864 | - (STB_KP222520933 * T12_0 865 | + STB_KP900968867 * T23_0) 866 | + T45; 867 | stb_real_t T60 = STB_KP623489801 * T52 + T53 - (STB_KP222520933 * T50 + STB_KP900968867 * T51); 868 | output[2 * count].imag = STB_KP974927912 * T54 - STB_KP781831482 * T56 - STB_KP433883739 * T55 + T60; 869 | output[5 * count].imag = T60 - (STB_KP974927912 * T54 - STB_KP781831482 * T56 - STB_KP433883739 * T55); 870 | stb_real_t T47 = STB_KP433883739 * T41 + STB_KP781831482 * T38_0 + STB_KP974927912 * T44; 871 | output[6 * count].real = STB_KP623489801 * T12_0 872 | + T1_0 873 | - (STB_KP222520933 * T23_0 874 | + STB_KP900968867 * T34_0) 875 | - T47; 876 | output[count].real = STB_KP623489801 * T12_0 877 | + T1_0 878 | - (STB_KP222520933 * T23_0 879 | + STB_KP900968867 * T34_0) 880 | + T47; 881 | stb_real_t T58 = STB_KP623489801 * T50 + T53 - (STB_KP222520933 * T51 + STB_KP900968867 * T52); 882 | output[count].imag = STB_KP433883739 * T56 + STB_KP781831482 * T54 + STB_KP974927912 * T55 + T58; 883 | output[6 * count].imag = T58 - (STB_KP433883739 * T56 + STB_KP781831482 * T54 + STB_KP974927912 * T55); 884 | stb_real_t T49 = STB_KP974927912 * T41 + STB_KP433883739 * T38_0 - STB_KP781831482 * T44; 885 | output[4 * count].real = STB_KP623489801 * T23_0 886 | + T1_0 887 | - (STB_KP900968867 * T12_0 888 | + STB_KP222520933 * T34_0) 889 | - T49; 890 | output[3 * count].real = STB_KP623489801 * T23_0 891 | + T1_0 892 | - (STB_KP900968867 * T12_0 893 | + STB_KP222520933 * T34_0) 894 | + T49; 895 | stb_real_t T62 = STB_KP623489801 * T51 + T53 - (STB_KP900968867 * T50 + STB_KP222520933 * T52); 896 | output[3 * count].imag = STB_KP974927912 * T56 + STB_KP433883739 * T54 - STB_KP781831482 * T55 + T62; 897 | output[4 * count].imag = T62 898 | - (STB_KP974927912 * T56 899 | + STB_KP433883739 * T54 900 | - STB_KP781831482 * T55); 901 | ++m; 902 | ++output; 903 | tw += 6; 904 | } 905 | } 906 | 907 | void stb_radix_8_dit(const cmplx* tw, cmplx* out, int count) 908 | { 909 | int m; 910 | cmplx* output; 911 | stb_real_t T2 = out[4 * count].real; 912 | stb_real_t T3 = out[0].real + T2; 913 | stb_real_t T23 = out[0].real - T2; 914 | stb_real_t T16 = out[0].imag; 915 | stb_real_t T17 = out[4 * count].imag; 916 | stb_real_t T4 = out[2 * count].real; 917 | stb_real_t T5 = out[6 * count].real; 918 | stb_real_t T19 = out[2 * count].imag; 919 | stb_real_t T20 = out[6 * count].imag; 920 | stb_real_t T11 = out[7 * count].real; 921 | stb_real_t T12 = out[3 * count].real; 922 | stb_real_t T32 = out[7 * count].imag; 923 | stb_real_t T33 = out[3 * count].imag; 924 | stb_real_t T35 = T11 - T12 - (T32 - T33); 925 | stb_real_t T43 = T11 - T12 + T32 - T33; 926 | stb_real_t T8 = out[count].real; 927 | stb_real_t T9 = out[5 * count].real; 928 | stb_real_t T27 = out[count].imag; 929 | stb_real_t T28 = out[5 * count].imag; 930 | stb_real_t T30 = T8 - T9 + T27 - T28; 931 | stb_real_t T42 = T27 - T28 - (T8 - T9); 932 | stb_real_t T7 = T3 + T4 + T5; 933 | stb_real_t T14 = T8 + T9 + T11 + T12; 934 | out[4 * count].real = T7 - T14; 935 | out[0].real = T7 + T14; 936 | out[4 * count].imag = T16 + T17 + T19 + T20 - (T27 + T28 + T32 + T33); 937 | out[0].imag = T16 + T17 + T19 + T20 + T27 + T28 + T32 + T33; 938 | stb_real_t T15 = T11 + T12 - (T8 + T9); 939 | stb_real_t T22 = T16 + T17 - (T19 + T20); 940 | out[2 * count].imag = T15 + T22; 941 | out[6 * count].imag = T22 - T15; 942 | stb_real_t T47 = T3 - (T4 + T5); 943 | stb_real_t T50 = T27 + T28 - (T32 + T33); 944 | out[6 * count].real = T47 - T50; 945 | out[2 * count].real = T47 + T50; 946 | stb_real_t T36 = (T30 + T35) * STB_KP707106781; 947 | out[5 * count].real = T23 + T19 - T20 - T36; 948 | out[count].real = T23 + T19 - T20 + T36; 949 | stb_real_t T46 = (T42 + T43) * STB_KP707106781; 950 | out[5 * count].imag = T16 - T17 - (T4 - T5) - T46; 951 | out[count].imag = T16 - T17 - (T4 - T5) + T46; 952 | stb_real_t T39 = T4 - T5 + T16 - T17; 953 | stb_real_t T40 = (T35 - T30) * STB_KP707106781; 954 | out[7 * count].imag = T39 - T40; 955 | out[3 * count].imag = T39 + T40; 956 | stb_real_t T41 = T23 - (T19 - T20); 957 | stb_real_t T44 = (T42 - T43) * STB_KP707106781; 958 | out[7 * count].real = T41 - T44; 959 | out[3 * count].real = T41 + T44; 960 | output = out + 1; 961 | m = 1; 962 | while (m < count) { 963 | stb_real_t T70 = output[0].imag; 964 | stb_real_t T3_0 = output[4 * count].real; 965 | stb_real_t T5_0 = output[4 * count].imag; 966 | stb_real_t T2_0 = tw[3].real; 967 | stb_real_t T4_0 = tw[3].imag; 968 | stb_real_t T6_0 = T4_0 * T5_0 + T2_0 * T3_0; 969 | stb_real_t T7_0 = output[0].real + T6_0; 970 | stb_real_t T76 = T70 - (T2_0 * T5_0 - T4_0 * T3_0); 971 | stb_real_t T43_0 = output[0].real - T6_0; 972 | stb_real_t T71 = T2_0 * T5_0 - T4_0 * T3_0 + T70; 973 | stb_real_t T32_0 = output[7 * count].real; 974 | stb_real_t T34_0 = output[7 * count].imag; 975 | stb_real_t T31_0 = tw[6].real; 976 | stb_real_t T33_0 = tw[6].imag; 977 | stb_real_t T37_0 = output[3 * count].real; 978 | stb_real_t T39_0 = output[3 * count].imag; 979 | stb_real_t T36_0 = tw[2].real; 980 | stb_real_t T38_0 = tw[2].imag; 981 | stb_real_t T40_0 = T38_0 * T39_0 + T36_0 * T37_0; 982 | stb_real_t T55 = T36_0 * T39_0 - T38_0 * T37_0; 983 | stb_real_t T41_0 = T33_0 * T34_0 + T31_0 * T32_0 + T40_0; 984 | stb_real_t T65 = T31_0 * T34_0 - T33_0 * T32_0 + T55; 985 | stb_real_t T53 = T33_0 * T34_0 + T31_0 * T32_0 - T40_0; 986 | stb_real_t T56 = T31_0 * T34_0 - T33_0 * T32_0 - T55; 987 | stb_real_t T9_0 = output[2 * count].real; 988 | stb_real_t T11_0 = output[2 * count].imag; 989 | stb_real_t T8_0 = tw[1].real; 990 | stb_real_t T10_0 = tw[1].imag; 991 | stb_real_t T14_0 = output[6 * count].real; 992 | stb_real_t T16_0 = output[6 * count].imag; 993 | stb_real_t T13_0 = tw[5].real; 994 | stb_real_t T15_0 = tw[5].imag; 995 | stb_real_t T17_0 = T15_0 * T16_0 + T13_0 * T14_0; 996 | stb_real_t T45_0 = T13_0 * T16_0 - T15_0 * T14_0; 997 | stb_real_t T18_0 = T10_0 * T11_0 + T8_0 * T9_0 + T17_0; 998 | stb_real_t T77 = T10_0 * T11_0 + T8_0 * T9_0 - T17_0; 999 | stb_real_t T46_0 = T8_0 * T11_0 - T10_0 * T9_0 - T45_0; 1000 | stb_real_t T68 = T8_0 * T11_0 - T10_0 * T9_0 + T45_0; 1001 | stb_real_t T21_0 = output[count].real; 1002 | stb_real_t T23_0 = output[count].imag; 1003 | stb_real_t T22_0 = tw[0].imag; 1004 | stb_real_t T26_0 = output[5 * count].real; 1005 | stb_real_t T28_0 = output[5 * count].imag; 1006 | stb_real_t T25_0 = tw[4].real; 1007 | stb_real_t T27_0 = tw[4].imag; 1008 | stb_real_t T29_0 = T27_0 * T28_0 + T25_0 * T26_0; 1009 | stb_real_t T50_0 = T25_0 * T28_0 - T27_0 * T26_0; 1010 | stb_real_t T30_0 = T22_0 * T23_0 + tw[0].real * T21_0 + T29_0; 1011 | stb_real_t T64 = tw[0].real * T23_0 - T22_0 * T21_0 + T50_0; 1012 | stb_real_t T48_0 = T22_0 * T23_0 + tw[0].real * T21_0 - T29_0; 1013 | stb_real_t T51_0 = tw[0].real * T23_0 - T22_0 * T21_0 - T50_0; 1014 | stb_real_t T19_0 = T7_0 + T18_0; 1015 | stb_real_t T42_0 = T30_0 + T41_0; 1016 | output[4 * count].real = T19_0 - T42_0; 1017 | output[0].real = T19_0 + T42_0; 1018 | output[0].imag = T64 + T65 + T68 + T71; 1019 | output[4 * count].imag = T68 + T71 - (T64 + T65); 1020 | output[6 * count].real = T7_0 - T18_0 - (T64 - T65); 1021 | output[2 * count].real = T7_0 - T18_0 + T64 - T65; 1022 | output[2 * count].imag = T41_0 - T30_0 + T71 - T68; 1023 | output[6 * count].imag = T71 - T68 - (T41_0 - T30_0); 1024 | stb_real_t T62 = (T51_0 - T48_0 - (T53 + T56)) * STB_KP707106781; 1025 | stb_real_t T75 = (T51_0 - T48_0 + T53 + T56) * STB_KP707106781; 1026 | output[7 * count].real = T43_0 - T46_0 - T62; 1027 | output[5 * count].imag = T76 - T77 - T75; 1028 | output[3 * count].real = T43_0 - T46_0 + T62; 1029 | output[count].imag = T75 + T76 - T77; 1030 | stb_real_t T58 = (T48_0 + T51_0 + T53 - T56) * STB_KP707106781; 1031 | stb_real_t T79 = (T53 - T56 - (T48_0 + T51_0)) * STB_KP707106781; 1032 | output[5 * count].real = T43_0 + T46_0 - T58; 1033 | output[7 * count].imag = T77 + T76 - T79; 1034 | output[count].real = T43_0 + T46_0 + T58; 1035 | output[3 * count].imag = T79 + T77 + T76; 1036 | ++m; 1037 | ++output; 1038 | tw += 7; 1039 | } 1040 | } 1041 | 1042 | void stb_radix_2_idit(const cmplx* tw, cmplx* out, int count) 1043 | { 1044 | int m; 1045 | cmplx* output; 1046 | stb_real_t T1 = out[0].real; 1047 | stb_real_t T2 = out[count].real; 1048 | out[count].real = out[0].real - T2; 1049 | out[0].real = T1 + T2; 1050 | stb_real_t T3 = out[0].imag; 1051 | stb_real_t T4 = out[count].imag; 1052 | out[count].imag = T3 - T4; 1053 | out[0].imag = T3 + T4; 1054 | output = out + 1; 1055 | m = 1; 1056 | while (m < count) { 1057 | stb_real_t T1_0 = output[0].real; 1058 | stb_real_t T8 = output[0].imag; 1059 | stb_real_t T3_0 = output[count].real; 1060 | stb_real_t T5 = output[count].imag; 1061 | stb_real_t T4_0 = tw[0].imag; 1062 | stb_real_t T6 = tw[0].real * T3_0 - T4_0 * T5; 1063 | stb_real_t T7 = tw[0].real * T5 + T4_0 * T3_0; 1064 | output[count].real = output[0].real - T6; 1065 | output[count].imag = T8 - T7; 1066 | output[0].real = T1_0 + T6; 1067 | output[0].imag = T7 + T8; 1068 | ++m; 1069 | ++output; 1070 | ++tw; 1071 | } 1072 | } 1073 | 1074 | void stb_radix_3_idit(const cmplx* tw, cmplx* out, int count) 1075 | { 1076 | int m; 1077 | cmplx* output; 1078 | stb_real_t T1 = out[0].real; 1079 | stb_real_t T6 = out[0].imag; 1080 | stb_real_t T2 = out[count].real; 1081 | stb_real_t T3 = out[2 * count].real; 1082 | stb_real_t T5 = (T2 - T3) * STB_KP866025403; 1083 | stb_real_t T7 = out[count].imag; 1084 | stb_real_t T8 = out[2 * count].imag; 1085 | stb_real_t T12 = (T8 - T7) * STB_KP866025403; 1086 | out[0].real = out[0].real + T2 + T3; 1087 | out[0].imag = T6 + T7 + T8; 1088 | stb_real_t T10 = T6 - STB_KP5 * (T7 + T8); 1089 | out[count].imag = T5 + T10; 1090 | out[2 * count].imag = T10 - T5; 1091 | stb_real_t T11 = T1 - STB_KP5 * (T2 + T3); 1092 | out[2 * count].real = T11 - T12; 1093 | out[count].real = T11 + T12; 1094 | output = out + 1; 1095 | m = 1; 1096 | while (m < count) { 1097 | stb_real_t T1_0 = output[0].real; 1098 | stb_real_t T18 = output[0].imag; 1099 | stb_real_t T3_0 = output[count].real; 1100 | stb_real_t T5_0 = output[count].imag; 1101 | stb_real_t T4_0 = tw[0].imag; 1102 | stb_real_t T6_0 = tw[0].real * T3_0 - T4_0 * T5_0; 1103 | stb_real_t T15 = tw[0].real * T5_0 + T4_0 * T3_0; 1104 | stb_real_t T8_0 = output[2 * count].real; 1105 | stb_real_t T10_0 = output[2 * count].imag; 1106 | stb_real_t T7_0 = tw[1].real; 1107 | stb_real_t T9_0 = tw[1].imag; 1108 | stb_real_t T11_0 = T7_0 * T8_0 - T9_0 * T10_0; 1109 | stb_real_t T14 = T7_0 * T10_0 + T9_0 * T8_0; 1110 | stb_real_t T12_0 = T6_0 + T11_0; 1111 | stb_real_t T17 = T15 + T14; 1112 | output[0].real = output[0].real + T12_0; 1113 | output[0].imag = T17 + T18; 1114 | stb_real_t T16 = (T14 - T15) * STB_KP866025403; 1115 | output[2 * count].real = T1_0 - STB_KP5 * T12_0 - T16; 1116 | output[count].real = T1_0 - STB_KP5 * T12_0 + T16; 1117 | stb_real_t T20 = T18 - STB_KP5 * T17; 1118 | output[count].imag = (T6_0 - T11_0) * STB_KP866025403 + T20; 1119 | output[2 * count].imag = T20 - (T6_0 - T11_0) * STB_KP866025403; 1120 | ++m; 1121 | ++output; 1122 | tw += 2; 1123 | } 1124 | } 1125 | 1126 | void stb_radix_4_idit(const cmplx* tw, cmplx* out, int count) 1127 | { 1128 | int m; 1129 | cmplx* output; 1130 | stb_real_t T2 = out[2 * count].real; 1131 | stb_real_t T3 = out[0].real + T2; 1132 | stb_real_t T11 = out[0].real - T2; 1133 | stb_real_t T8 = out[0].imag; 1134 | stb_real_t T9 = out[2 * count].imag; 1135 | stb_real_t T4 = out[count].real; 1136 | stb_real_t T5 = out[3 * count].real; 1137 | stb_real_t T12 = out[count].imag; 1138 | stb_real_t T13 = out[3 * count].imag; 1139 | out[2 * count].real = T3 - (T4 + T5); 1140 | out[2 * count].imag = T8 + T9 - (T12 + T13); 1141 | out[0].real = T3 + T4 + T5; 1142 | out[0].imag = T8 + T9 + T12 + T13; 1143 | out[count].imag = T4 - T5 + T8 - T9; 1144 | out[count].real = T11 - (T12 - T13); 1145 | out[3 * count].imag = T8 - T9 - (T4 - T5); 1146 | out[3 * count].real = T11 + T12 - T13; 1147 | output = out + 1; 1148 | m = 1; 1149 | while (m < count) { 1150 | stb_real_t T1_0 = output[0].real; 1151 | stb_real_t T25 = output[0].imag; 1152 | stb_real_t T3_0 = output[2 * count].real; 1153 | stb_real_t T5_0 = output[2 * count].imag; 1154 | stb_real_t T2_0 = tw[1].real; 1155 | stb_real_t T4_0 = tw[1].imag; 1156 | stb_real_t T6_0 = T2_0 * T3_0 - T4_0 * T5_0; 1157 | stb_real_t T24 = T2_0 * T5_0 + T4_0 * T3_0; 1158 | stb_real_t T9_0 = output[count].real; 1159 | stb_real_t T11_0 = output[count].imag; 1160 | stb_real_t T10_0 = tw[0].imag; 1161 | stb_real_t T12_0 = tw[0].real * T9_0 - T10_0 * T11_0; 1162 | stb_real_t T20 = tw[0].real * T11_0 + T10_0 * T9_0; 1163 | stb_real_t T14_0 = output[3 * count].real; 1164 | stb_real_t T16_0 = output[3 * count].imag; 1165 | stb_real_t T13_0 = tw[2].real; 1166 | stb_real_t T15_0 = tw[2].imag; 1167 | stb_real_t T17 = T13_0 * T14_0 - T15_0 * T16_0; 1168 | stb_real_t T21 = T13_0 * T16_0 + T15_0 * T14_0; 1169 | stb_real_t T18 = T12_0 + T17; 1170 | output[2 * count].real = output[0].real + T6_0 - T18; 1171 | output[0].real = T1_0 + T6_0 + T18; 1172 | output[0].imag = T20 + T21 + T24 + T25; 1173 | output[2 * count].imag = T24 + T25 - (T20 + T21); 1174 | output[count].real = T1_0 - T6_0 - (T20 - T21); 1175 | output[3 * count].real = T1_0 - T6_0 + T20 - T21; 1176 | output[count].imag = T12_0 - T17 + T25 - T24; 1177 | output[3 * count].imag = T25 - T24 - (T12_0 - T17); 1178 | ++m; 1179 | ++output; 1180 | tw += 3; 1181 | } 1182 | } 1183 | 1184 | void stb_radix_5_idit(const cmplx* tw, cmplx* out, int count) 1185 | { 1186 | int m; 1187 | cmplx* output; 1188 | stb_real_t T1 = out[0].real; 1189 | stb_real_t T27 = out[0].imag; 1190 | stb_real_t T2 = out[count].real; 1191 | stb_real_t T3 = out[4 * count].real; 1192 | stb_real_t T5 = out[2 * count].real; 1193 | stb_real_t T6 = out[3 * count].real; 1194 | stb_real_t T8 = T2 + T3 + T5 + T6; 1195 | stb_real_t T10 = (T2 + T3 - (T5 + T6)) * STB_KP559016994; 1196 | stb_real_t T12 = out[count].imag; 1197 | stb_real_t T13 = out[4 * count].imag; 1198 | stb_real_t T15 = out[2 * count].imag; 1199 | stb_real_t T16 = out[3 * count].imag; 1200 | stb_real_t T28 = T12 + T13 + T15 + T16; 1201 | stb_real_t T26 = (T12 + T13 - (T15 + T16)) * STB_KP559016994; 1202 | out[0].real = out[0].real + T8; 1203 | out[0].imag = T27 + T28; 1204 | stb_real_t T18 = STB_KP587785252 * (T12 - T13) - STB_KP951056516 * (T15 - T16); 1205 | stb_real_t T20 = STB_KP587785252 * (T15 - T16) + STB_KP951056516 * (T12 - T13); 1206 | stb_real_t T19 = T10 + T1 - STB_KP25 * T8; 1207 | out[2 * count].real = T1 - STB_KP25 * T8 - T10 - T18; 1208 | out[4 * count].real = T19 + T20; 1209 | out[3 * count].real = T1 - STB_KP25 * T8 - T10 + T18; 1210 | out[count].real = T19 - T20; 1211 | stb_real_t T31 = STB_KP587785252 * (T2 - T3) - STB_KP951056516 * (T5 - T6); 1212 | stb_real_t T30 = T26 + T27 - STB_KP25 * T28; 1213 | stb_real_t T32 = T27 - STB_KP25 * T28 - T26; 1214 | out[count].imag = STB_KP587785252 * (T5 - T6) + STB_KP951056516 * (T2 - T3) + T30; 1215 | out[3 * count].imag = T32 - T31; 1216 | out[4 * count].imag = T30 - (STB_KP587785252 * (T5 - T6) + STB_KP951056516 * (T2 - T3)); 1217 | out[2 * count].imag = T31 + T32; 1218 | output = out + 1; 1219 | m = 1; 1220 | while (m < count) { 1221 | stb_real_t T1_0 = output[0].real; 1222 | stb_real_t T40 = output[0].imag; 1223 | stb_real_t T3_0 = output[count].real; 1224 | stb_real_t T5_0 = output[count].imag; 1225 | stb_real_t T4_0 = tw[0].imag; 1226 | stb_real_t T19_0 = output[3 * count].real; 1227 | stb_real_t T21_0 = output[3 * count].imag; 1228 | stb_real_t T18_0 = tw[2].real; 1229 | stb_real_t T20_0 = tw[2].imag; 1230 | stb_real_t T22_0 = T18_0 * T19_0 - T20_0 * T21_0; 1231 | stb_real_t T32_0 = T18_0 * T21_0 + T20_0 * T19_0; 1232 | stb_real_t T8_0 = output[4 * count].real; 1233 | stb_real_t T10_0 = output[4 * count].imag; 1234 | stb_real_t T7_0 = tw[3].real; 1235 | stb_real_t T9_0 = tw[3].imag; 1236 | stb_real_t T11_0 = T7_0 * T8_0 - T9_0 * T10_0; 1237 | stb_real_t T29_0 = T7_0 * T10_0 + T9_0 * T8_0; 1238 | stb_real_t T14_0 = output[2 * count].real; 1239 | stb_real_t T16_0 = output[2 * count].imag; 1240 | stb_real_t T13_0 = tw[1].real; 1241 | stb_real_t T15_0 = tw[1].imag; 1242 | stb_real_t T30_0 = tw[0].real * T5_0 + T4_0 * T3_0 - T29_0; 1243 | stb_real_t T33 = T13_0 * T16_0 + T15_0 * T14_0 - T32_0; 1244 | stb_real_t T42 = T13_0 * T14_0 - T15_0 * T16_0 - T22_0; 1245 | stb_real_t T41 = tw[0].real * T3_0 - T4_0 * T5_0 - T11_0; 1246 | stb_real_t T37 = tw[0].real * T5_0 + T4_0 * T3_0 + T29_0; 1247 | stb_real_t T38 = T13_0 * T16_0 + T15_0 * T14_0 + T32_0; 1248 | stb_real_t T39 = T37 + T38; 1249 | stb_real_t T12_0 = tw[0].real * T3_0 - T4_0 * T5_0 + T11_0; 1250 | stb_real_t T23_0 = T13_0 * T14_0 - T15_0 * T16_0 + T22_0; 1251 | stb_real_t T24_0 = T12_0 + T23_0; 1252 | output[0].real = output[0].real + T24_0; 1253 | output[0].imag = T39 + T40; 1254 | stb_real_t T34 = STB_KP587785252 * T30_0 - STB_KP951056516 * T33; 1255 | stb_real_t T36 = STB_KP587785252 * T33 + STB_KP951056516 * T30_0; 1256 | stb_real_t T27_0 = T1_0 - STB_KP25 * T24_0 - (T12_0 - T23_0) * STB_KP559016994; 1257 | stb_real_t T35 = (T12_0 - T23_0) * STB_KP559016994 + T1_0 - STB_KP25 * T24_0; 1258 | output[2 * count].real = T27_0 - T34; 1259 | output[4 * count].real = T35 + T36; 1260 | output[3 * count].real = T27_0 + T34; 1261 | output[count].real = T35 - T36; 1262 | stb_real_t T47 = STB_KP587785252 * T41 - STB_KP951056516 * T42; 1263 | stb_real_t T46 = (T37 - T38) * STB_KP559016994 + T40 - STB_KP25 * T39; 1264 | stb_real_t T48 = T40 - STB_KP25 * T39 - (T37 - T38) * STB_KP559016994; 1265 | output[count].imag = STB_KP587785252 * T42 + STB_KP951056516 * T41 + T46; 1266 | output[3 * count].imag = T48 - T47; 1267 | output[4 * count].imag = T46 - (STB_KP587785252 * T42 + STB_KP951056516 * T41); 1268 | output[2 * count].imag = T47 + T48; 1269 | ++m; 1270 | ++output; 1271 | tw += 4; 1272 | } 1273 | } 1274 | 1275 | void stb_radix_6_idit(const cmplx* tw, cmplx* out, int count) 1276 | { 1277 | int m; 1278 | cmplx* output; 1279 | stb_real_t T2 = out[3 * count].real; 1280 | stb_real_t T3 = out[0].real - T2; 1281 | stb_real_t T11 = out[0].real + T2; 1282 | stb_real_t T24 = out[0].imag; 1283 | stb_real_t T25 = out[3 * count].imag; 1284 | stb_real_t T4 = out[2 * count].real; 1285 | stb_real_t T5 = out[5 * count].real; 1286 | stb_real_t T7 = out[4 * count].real; 1287 | stb_real_t T8 = out[count].real; 1288 | stb_real_t T10 = T4 - T5 + T7 - T8; 1289 | stb_real_t T14 = T4 + T5 + T7 + T8; 1290 | stb_real_t T16 = out[4 * count].imag; 1291 | stb_real_t T17 = out[count].imag; 1292 | stb_real_t T19 = out[2 * count].imag; 1293 | stb_real_t T20 = out[5 * count].imag; 1294 | stb_real_t T27 = T19 - T20 + T16 - T17; 1295 | stb_real_t T32 = T19 + T20 + T16 + T17; 1296 | out[3 * count].real = T3 + T10; 1297 | out[3 * count].imag = T24 - T25 + T27; 1298 | out[0].real = T11 + T14; 1299 | out[0].imag = T24 + T25 + T32; 1300 | stb_real_t T22 = (T16 - T17 - (T19 - T20)) * STB_KP866025403; 1301 | out[5 * count].real = T3 - STB_KP5 * T10 - T22; 1302 | out[count].real = T3 - STB_KP5 * T10 + T22; 1303 | stb_real_t T23 = (T4 - T5 - (T7 - T8)) * STB_KP866025403; 1304 | stb_real_t T28 = T24 - T25 - STB_KP5 * T27; 1305 | out[count].imag = T23 + T28; 1306 | out[5 * count].imag = T28 - T23; 1307 | stb_real_t T33 = T24 + T25 - STB_KP5 * T32; 1308 | stb_real_t T34 = (T4 + T5 - (T7 + T8)) * STB_KP866025403; 1309 | out[2 * count].imag = T33 - T34; 1310 | out[4 * count].imag = T34 + T33; 1311 | stb_real_t T36 = (T16 + T17 - (T19 + T20)) * STB_KP866025403; 1312 | out[2 * count].real = T11 - STB_KP5 * T14 - T36; 1313 | out[4 * count].real = T11 - STB_KP5 * T14 + T36; 1314 | output = out + 1; 1315 | m = 1; 1316 | while (m < count) { 1317 | stb_real_t T49 = output[0].imag; 1318 | stb_real_t T3_0 = output[3 * count].real; 1319 | stb_real_t T5_0 = output[3 * count].imag; 1320 | stb_real_t T2_0 = tw[2].real; 1321 | stb_real_t T4_0 = tw[2].imag; 1322 | stb_real_t T6_0 = T2_0 * T3_0 - T4_0 * T5_0; 1323 | stb_real_t T54 = T49 - (T2_0 * T5_0 + T4_0 * T3_0); 1324 | stb_real_t T31_0 = output[0].real + T6_0; 1325 | stb_real_t T50 = T2_0 * T5_0 + T4_0 * T3_0 + T49; 1326 | stb_real_t T20_0 = output[4 * count].real; 1327 | stb_real_t T22_0 = output[4 * count].imag; 1328 | stb_real_t T19_0 = tw[3].real; 1329 | stb_real_t T21_0 = tw[3].imag; 1330 | stb_real_t T25_0 = output[count].real; 1331 | stb_real_t T27_0 = output[count].imag; 1332 | stb_real_t T26_0 = tw[0].imag; 1333 | stb_real_t T28_0 = tw[0].real * T25_0 - T26_0 * T27_0; 1334 | stb_real_t T37 = tw[0].real * T27_0 + T26_0 * T25_0; 1335 | stb_real_t T29_0 = T19_0 * T20_0 - T21_0 * T22_0 - T28_0; 1336 | stb_real_t T44 = T19_0 * T22_0 + T21_0 * T20_0 + T37; 1337 | stb_real_t T33_0 = T19_0 * T20_0 - T21_0 * T22_0 + T28_0; 1338 | stb_real_t T9_0 = output[2 * count].real; 1339 | stb_real_t T11_0 = output[2 * count].imag; 1340 | stb_real_t T8_0 = tw[1].real; 1341 | stb_real_t T10_0 = tw[1].imag; 1342 | stb_real_t T14_0 = output[5 * count].real; 1343 | stb_real_t T16_0 = output[5 * count].imag; 1344 | stb_real_t T13_0 = tw[4].real; 1345 | stb_real_t T15_0 = tw[4].imag; 1346 | stb_real_t T17_0 = T13_0 * T14_0 - T15_0 * T16_0; 1347 | stb_real_t T40 = T13_0 * T16_0 + T15_0 * T14_0; 1348 | stb_real_t T45 = T8_0 * T11_0 + T10_0 * T9_0 + T40; 1349 | stb_real_t T32_0 = T8_0 * T9_0 - T10_0 * T11_0 + T17_0; 1350 | stb_real_t T41 = T8_0 * T11_0 + T10_0 * T9_0 - T40; 1351 | stb_real_t T42 = (T19_0 * T22_0 + T21_0 * T20_0 - T37 - T41) * STB_KP866025403; 1352 | stb_real_t T30_0 = T8_0 * T9_0 - T10_0 * T11_0 - T17_0 + T29_0; 1353 | stb_real_t T35_0 = output[0].real - T6_0 - STB_KP5 * T30_0; 1354 | output[3 * count].real = output[0].real - T6_0 + T30_0; 1355 | output[count].real = T35_0 + T42; 1356 | output[5 * count].real = T35_0 - T42; 1357 | stb_real_t T53 = (T8_0 * T9_0 - T10_0 * T11_0 - T17_0 - T29_0) * STB_KP866025403; 1358 | stb_real_t T55 = T41 + T19_0 * T22_0 + T21_0 * T20_0 - T37; 1359 | stb_real_t T56 = T54 - STB_KP5 * T55; 1360 | output[count].imag = T53 + T56; 1361 | output[3 * count].imag = T55 + T54; 1362 | output[5 * count].imag = T56 - T53; 1363 | stb_real_t T46 = (T44 - T45) * STB_KP866025403; 1364 | stb_real_t T43 = T31_0 - STB_KP5 * (T32_0 + T33_0); 1365 | output[0].real = T31_0 + T32_0 + T33_0; 1366 | output[4 * count].real = T43 + T46; 1367 | output[2 * count].real = T43 - T46; 1368 | stb_real_t T52 = (T32_0 - T33_0) * STB_KP866025403; 1369 | stb_real_t T51 = T50 - STB_KP5 * (T45 + T44); 1370 | output[0].imag = T45 + T44 + T50; 1371 | output[4 * count].imag = T52 + T51; 1372 | output[2 * count].imag = T51 - T52; 1373 | ++m; 1374 | ++output; 1375 | tw += 5; 1376 | } 1377 | } 1378 | 1379 | void stb_radix_7_idit(const cmplx* tw, cmplx* out, int count) 1380 | { 1381 | int m; 1382 | cmplx* output; 1383 | stb_real_t T1 = out[0].real; 1384 | stb_real_t T15 = out[0].imag; 1385 | stb_real_t T2 = out[count].real; 1386 | stb_real_t T3 = out[6 * count].real; 1387 | stb_real_t T22 = out[count].imag; 1388 | stb_real_t T23 = out[6 * count].imag; 1389 | stb_real_t T5 = out[2 * count].real; 1390 | stb_real_t T6 = out[5 * count].real; 1391 | stb_real_t T16 = out[2 * count].imag; 1392 | stb_real_t T17 = out[5 * count].imag; 1393 | stb_real_t T8 = out[3 * count].real; 1394 | stb_real_t T9 = out[4 * count].real; 1395 | stb_real_t T19 = out[3 * count].imag; 1396 | stb_real_t T20 = out[4 * count].imag; 1397 | out[0].real = out[0].real + T2 + T3 + T5 + T6 + T8 + T9; 1398 | out[0].imag = T15 + T22 + T23 + T16 + T17 + T19 + T20; 1399 | stb_real_t T25 = STB_KP623489801 * (T16 + T17) + T15 - (STB_KP900968867 * (T22 + T23) + STB_KP222520933 * (T19 + T20)); 1400 | out[3 * count].imag = STB_KP974927912 * (T8 - T9) 1401 | + STB_KP433883739 * (T2 - T3) 1402 | - STB_KP781831482 * (T5 - T6) 1403 | + T25; 1404 | out[4 * count].imag = T25 1405 | - (STB_KP974927912 * (T8 - T9) 1406 | + STB_KP433883739 * (T2 - T3) 1407 | - STB_KP781831482 * (T5 - T6)); 1408 | stb_real_t T38 = STB_KP974927912 * (T20 - T19) + STB_KP433883739 * (T23 - T22) - STB_KP781831482 * (T17 - T16); 1409 | out[4 * count].real = STB_KP623489801 * (T5 + T6) 1410 | + T1 1411 | - (STB_KP900968867 * (T2 + T3) 1412 | + STB_KP222520933 * (T8 + T9)) 1413 | - T38; 1414 | out[3 * count].real = STB_KP623489801 * (T5 + T6) 1415 | + T1 1416 | - (STB_KP900968867 * (T2 + T3) 1417 | + STB_KP222520933 * (T8 + T9)) 1418 | + T38; 1419 | stb_real_t T27 = STB_KP623489801 * (T22 + T23) + T15 - (STB_KP222520933 * (T16 + T17) + STB_KP900968867 * (T19 + T20)); 1420 | out[count].imag = STB_KP433883739 * (T8 - T9) 1421 | + STB_KP781831482 * (T2 - T3) 1422 | + STB_KP974927912 * (T5 - T6) 1423 | + T27; 1424 | out[6 * count].imag = T27 1425 | - (STB_KP433883739 * (T8 - T9) 1426 | + STB_KP781831482 * (T2 - T3) 1427 | + STB_KP974927912 * (T5 - T6)); 1428 | stb_real_t T36 = STB_KP433883739 * (T20 - T19) + STB_KP781831482 * (T23 - T22) + STB_KP974927912 * (T17 - T16); 1429 | out[6 * count].real = STB_KP623489801 * (T2 + T3) 1430 | + T1 1431 | - (STB_KP222520933 * (T5 + T6) 1432 | + STB_KP900968867 * (T8 + T9)) 1433 | - T36; 1434 | out[count].real = STB_KP623489801 * (T2 + T3) 1435 | + T1 1436 | - (STB_KP222520933 * (T5 + T6) 1437 | + STB_KP900968867 * (T8 + T9)) 1438 | + T36; 1439 | stb_real_t T28 = STB_KP974927912 * (T2 - T3) - STB_KP781831482 * (T8 - T9) - STB_KP433883739 * (T5 - T6); 1440 | stb_real_t T29 = STB_KP623489801 * (T19 + T20) + T15 - (STB_KP222520933 * (T22 + T23) + STB_KP900968867 * (T16 + T17)); 1441 | out[2 * count].imag = T28 + T29; 1442 | out[5 * count].imag = T29 - T28; 1443 | stb_real_t T34 = STB_KP974927912 * (T23 - T22) - STB_KP781831482 * (T20 - T19) - STB_KP433883739 * (T17 - T16); 1444 | stb_real_t T30 = STB_KP623489801 * (T8 + T9) + T1 - (STB_KP222520933 * (T2 + T3) + STB_KP900968867 * (T5 + T6)); 1445 | out[5 * count].real = T30 - T34; 1446 | out[2 * count].real = T30 + T34; 1447 | output = out + 1; 1448 | m = 1; 1449 | while (m < count) { 1450 | stb_real_t T1_0 = output[0].real; 1451 | stb_real_t T53 = output[0].imag; 1452 | stb_real_t T3_0 = output[count].real; 1453 | stb_real_t T5_0 = output[count].imag; 1454 | stb_real_t T4_0 = tw[0].imag; 1455 | stb_real_t T8_0 = output[6 * count].real; 1456 | stb_real_t T10_0 = output[6 * count].imag; 1457 | stb_real_t T7_0 = tw[5].real; 1458 | stb_real_t T9_0 = tw[5].imag; 1459 | stb_real_t T11_0 = T7_0 * T8_0 - T9_0 * T10_0; 1460 | stb_real_t T12_0 = tw[0].real * T3_0 - T4_0 * T5_0 + T11_0; 1461 | stb_real_t T54 = tw[0].real * T3_0 - T4_0 * T5_0 - T11_0; 1462 | stb_real_t T38_0 = T7_0 * T10_0 + T9_0 * T8_0 - (tw[0].real * T5_0 + T4_0 * T3_0); 1463 | stb_real_t T50 = tw[0].real * T5_0 + T4_0 * T3_0 + T7_0 * T10_0 + T9_0 * T8_0; 1464 | stb_real_t T14_0 = output[2 * count].real; 1465 | stb_real_t T16_0 = output[2 * count].imag; 1466 | stb_real_t T13_0 = tw[1].real; 1467 | stb_real_t T15_0 = tw[1].imag; 1468 | stb_real_t T19_0 = output[5 * count].real; 1469 | stb_real_t T21_0 = output[5 * count].imag; 1470 | stb_real_t T18_0 = tw[4].real; 1471 | stb_real_t T20_0 = tw[4].imag; 1472 | stb_real_t T22_0 = T18_0 * T19_0 - T20_0 * T21_0; 1473 | stb_real_t T23_0 = T13_0 * T14_0 - T15_0 * T16_0 + T22_0; 1474 | stb_real_t T55 = T13_0 * T14_0 - T15_0 * T16_0 - T22_0; 1475 | stb_real_t T44 = T18_0 * T21_0 + T20_0 * T19_0 - (T13_0 * T16_0 + T15_0 * T14_0); 1476 | stb_real_t T51 = T13_0 * T16_0 + T15_0 * T14_0 + T18_0 * T21_0 + T20_0 * T19_0; 1477 | stb_real_t T25_0 = output[3 * count].real; 1478 | stb_real_t T27_0 = output[3 * count].imag; 1479 | stb_real_t T24_0 = tw[2].real; 1480 | stb_real_t T26_0 = tw[2].imag; 1481 | stb_real_t T30_0 = output[4 * count].real; 1482 | stb_real_t T32_0 = output[4 * count].imag; 1483 | stb_real_t T29_0 = tw[3].real; 1484 | stb_real_t T31_0 = tw[3].imag; 1485 | stb_real_t T33_0 = T29_0 * T30_0 - T31_0 * T32_0; 1486 | stb_real_t T34_0 = T24_0 * T25_0 - T26_0 * T27_0 + T33_0; 1487 | stb_real_t T56 = T24_0 * T25_0 - T26_0 * T27_0 - T33_0; 1488 | stb_real_t T41 = T29_0 * T32_0 + T31_0 * T30_0 - (T24_0 * T27_0 + T26_0 * T25_0); 1489 | stb_real_t T52 = T24_0 * T27_0 + T26_0 * T25_0 + T29_0 * T32_0 + T31_0 * T30_0; 1490 | output[0].real = output[0].real + T12_0 + T23_0 + T34_0; 1491 | output[0].imag = T50 + T51 + T52 + T53; 1492 | stb_real_t T45 = STB_KP974927912 * T38_0 - STB_KP781831482 * T41 - STB_KP433883739 * T44; 1493 | output[5 * count].real = STB_KP623489801 * T34_0 1494 | + T1_0 1495 | - (STB_KP222520933 * T12_0 1496 | + STB_KP900968867 * T23_0) 1497 | - T45; 1498 | output[2 * count].real = STB_KP623489801 * T34_0 1499 | + T1_0 1500 | - (STB_KP222520933 * T12_0 1501 | + STB_KP900968867 * T23_0) 1502 | + T45; 1503 | stb_real_t T60 = STB_KP623489801 * T52 + T53 - (STB_KP222520933 * T50 + STB_KP900968867 * T51); 1504 | output[2 * count].imag = STB_KP974927912 * T54 - STB_KP781831482 * T56 - STB_KP433883739 * T55 + T60; 1505 | output[5 * count].imag = T60 - (STB_KP974927912 * T54 - STB_KP781831482 * T56 - STB_KP433883739 * T55); 1506 | stb_real_t T47 = STB_KP433883739 * T41 + STB_KP781831482 * T38_0 + STB_KP974927912 * T44; 1507 | output[6 * count].real = STB_KP623489801 * T12_0 1508 | + T1_0 1509 | - (STB_KP222520933 * T23_0 1510 | + STB_KP900968867 * T34_0) 1511 | - T47; 1512 | output[count].real = STB_KP623489801 * T12_0 1513 | + T1_0 1514 | - (STB_KP222520933 * T23_0 1515 | + STB_KP900968867 * T34_0) 1516 | + T47; 1517 | stb_real_t T58 = STB_KP623489801 * T50 + T53 - (STB_KP222520933 * T51 + STB_KP900968867 * T52); 1518 | output[count].imag = STB_KP433883739 * T56 + STB_KP781831482 * T54 + STB_KP974927912 * T55 + T58; 1519 | output[6 * count].imag = T58 - (STB_KP433883739 * T56 + STB_KP781831482 * T54 + STB_KP974927912 * T55); 1520 | stb_real_t T49 = STB_KP974927912 * T41 + STB_KP433883739 * T38_0 - STB_KP781831482 * T44; 1521 | output[4 * count].real = STB_KP623489801 * T23_0 1522 | + T1_0 1523 | - (STB_KP900968867 * T12_0 1524 | + STB_KP222520933 * T34_0) 1525 | - T49; 1526 | output[3 * count].real = STB_KP623489801 * T23_0 1527 | + T1_0 1528 | - (STB_KP900968867 * T12_0 1529 | + STB_KP222520933 * T34_0) 1530 | + T49; 1531 | stb_real_t T62 = STB_KP623489801 * T51 + T53 - (STB_KP900968867 * T50 + STB_KP222520933 * T52); 1532 | output[3 * count].imag = STB_KP974927912 * T56 + STB_KP433883739 * T54 - STB_KP781831482 * T55 + T62; 1533 | output[4 * count].imag = T62 1534 | - (STB_KP974927912 * T56 1535 | + STB_KP433883739 * T54 1536 | - STB_KP781831482 * T55); 1537 | ++m; 1538 | ++output; 1539 | tw += 6; 1540 | } 1541 | } 1542 | 1543 | void stb_radix_8_idit(const cmplx* tw, cmplx* out, int count) 1544 | { 1545 | int m; 1546 | cmplx* output; 1547 | stb_real_t T2 = out[4 * count].real; 1548 | stb_real_t T3 = out[0].real + T2; 1549 | stb_real_t T37 = out[0].real - T2; 1550 | stb_real_t T16 = out[0].imag; 1551 | stb_real_t T17 = out[4 * count].imag; 1552 | stb_real_t T4 = out[2 * count].real; 1553 | stb_real_t T5 = out[6 * count].real; 1554 | stb_real_t T19 = out[2 * count].imag; 1555 | stb_real_t T20 = out[6 * count].imag; 1556 | stb_real_t T11 = out[7 * count].real; 1557 | stb_real_t T12 = out[3 * count].real; 1558 | stb_real_t T32 = out[7 * count].imag; 1559 | stb_real_t T33 = out[3 * count].imag; 1560 | stb_real_t T35 = T11 - T12 + T32 - T33; 1561 | stb_real_t T43 = T32 - T33 - (T11 - T12); 1562 | stb_real_t T8 = out[count].real; 1563 | stb_real_t T9 = out[5 * count].real; 1564 | stb_real_t T27 = out[count].imag; 1565 | stb_real_t T28 = out[5 * count].imag; 1566 | stb_real_t T30 = T8 - T9 - (T27 - T28); 1567 | stb_real_t T42 = T8 - T9 + T27 - T28; 1568 | stb_real_t T7 = T3 + T4 + T5; 1569 | stb_real_t T14 = T8 + T9 + T11 + T12; 1570 | out[4 * count].real = T7 - T14; 1571 | out[0].real = T7 + T14; 1572 | out[4 * count].imag = T16 + T17 + T19 + T20 - (T27 + T28 + T32 + T33); 1573 | out[0].imag = T16 + T17 + T19 + T20 + T27 + T28 + T32 + T33; 1574 | stb_real_t T15 = T8 + T9 - (T11 + T12); 1575 | stb_real_t T22 = T16 + T17 - (T19 + T20); 1576 | out[2 * count].imag = T15 + T22; 1577 | out[6 * count].imag = T22 - T15; 1578 | stb_real_t T51 = T3 - (T4 + T5); 1579 | stb_real_t T52 = T32 + T33 - (T27 + T28); 1580 | out[6 * count].real = T51 - T52; 1581 | out[2 * count].real = T51 + T52; 1582 | stb_real_t T36 = (T30 - T35) * STB_KP707106781; 1583 | out[7 * count].imag = T16 - T17 - (T4 - T5) - T36; 1584 | out[3 * count].imag = T16 - T17 - (T4 - T5) + T36; 1585 | stb_real_t T46 = (T43 - T42) * STB_KP707106781; 1586 | out[7 * count].real = T37 + T19 - T20 - T46; 1587 | out[3 * count].real = T37 + T19 - T20 + T46; 1588 | stb_real_t T39 = T37 - (T19 - T20); 1589 | stb_real_t T40 = (T30 + T35) * STB_KP707106781; 1590 | out[5 * count].real = T39 - T40; 1591 | out[count].real = T39 + T40; 1592 | stb_real_t T41 = T4 - T5 + T16 - T17; 1593 | stb_real_t T44 = (T42 + T43) * STB_KP707106781; 1594 | out[5 * count].imag = T41 - T44; 1595 | out[count].imag = T41 + T44; 1596 | output = out + 1; 1597 | m = 1; 1598 | while (m < count) { 1599 | stb_real_t T70 = output[0].imag; 1600 | stb_real_t T3_0 = output[4 * count].real; 1601 | stb_real_t T5_0 = output[4 * count].imag; 1602 | stb_real_t T2_0 = tw[3].real; 1603 | stb_real_t T4_0 = tw[3].imag; 1604 | stb_real_t T6_0 = T2_0 * T3_0 - T4_0 * T5_0; 1605 | stb_real_t T7_0 = output[0].real + T6_0; 1606 | stb_real_t T77 = T70 - (T2_0 * T5_0 + T4_0 * T3_0); 1607 | stb_real_t T43_0 = output[0].real - T6_0; 1608 | stb_real_t T71 = T2_0 * T5_0 + T4_0 * T3_0 + T70; 1609 | stb_real_t T32_0 = output[7 * count].real; 1610 | stb_real_t T34_0 = output[7 * count].imag; 1611 | stb_real_t T31_0 = tw[6].real; 1612 | stb_real_t T33_0 = tw[6].imag; 1613 | stb_real_t T37_0 = output[3 * count].real; 1614 | stb_real_t T39_0 = output[3 * count].imag; 1615 | stb_real_t T36_0 = tw[2].real; 1616 | stb_real_t T38_0 = tw[2].imag; 1617 | stb_real_t T40_0 = T36_0 * T37_0 - T38_0 * T39_0; 1618 | stb_real_t T55 = T36_0 * T39_0 + T38_0 * T37_0; 1619 | stb_real_t T41_0 = T31_0 * T32_0 - T33_0 * T34_0 + T40_0; 1620 | stb_real_t T64 = T31_0 * T34_0 + T33_0 * T32_0 + T55; 1621 | stb_real_t T53 = T31_0 * T32_0 - T33_0 * T34_0 - T40_0; 1622 | stb_real_t T56 = T31_0 * T34_0 + T33_0 * T32_0 - T55; 1623 | stb_real_t T9_0 = output[2 * count].real; 1624 | stb_real_t T11_0 = output[2 * count].imag; 1625 | stb_real_t T8_0 = tw[1].real; 1626 | stb_real_t T10_0 = tw[1].imag; 1627 | stb_real_t T14_0 = output[6 * count].real; 1628 | stb_real_t T16_0 = output[6 * count].imag; 1629 | stb_real_t T13_0 = tw[5].real; 1630 | stb_real_t T15_0 = tw[5].imag; 1631 | stb_real_t T17_0 = T13_0 * T14_0 - T15_0 * T16_0; 1632 | stb_real_t T45_0 = T13_0 * T16_0 + T15_0 * T14_0; 1633 | stb_real_t T18_0 = T8_0 * T9_0 - T10_0 * T11_0 + T17_0; 1634 | stb_real_t T76 = T8_0 * T9_0 - T10_0 * T11_0 - T17_0; 1635 | stb_real_t T46_0 = T8_0 * T11_0 + T10_0 * T9_0 - T45_0; 1636 | stb_real_t T68 = T8_0 * T11_0 + T10_0 * T9_0 + T45_0; 1637 | stb_real_t T21_0 = output[count].real; 1638 | stb_real_t T23_0 = output[count].imag; 1639 | stb_real_t T22_0 = tw[0].imag; 1640 | stb_real_t T26_0 = output[5 * count].real; 1641 | stb_real_t T28_0 = output[5 * count].imag; 1642 | stb_real_t T25_0 = tw[4].real; 1643 | stb_real_t T27_0 = tw[4].imag; 1644 | stb_real_t T29_0 = T25_0 * T26_0 - T27_0 * T28_0; 1645 | stb_real_t T50_0 = T25_0 * T28_0 + T27_0 * T26_0; 1646 | stb_real_t T30_0 = tw[0].real * T21_0 - T22_0 * T23_0 + T29_0; 1647 | stb_real_t T65 = tw[0].real * T23_0 + T22_0 * T21_0 + T50_0; 1648 | stb_real_t T48_0 = tw[0].real * T21_0 - T22_0 * T23_0 - T29_0; 1649 | stb_real_t T51_0 = tw[0].real * T23_0 + T22_0 * T21_0 - T50_0; 1650 | stb_real_t T19_0 = T7_0 + T18_0; 1651 | stb_real_t T42_0 = T30_0 + T41_0; 1652 | output[4 * count].real = T19_0 - T42_0; 1653 | output[0].real = T19_0 + T42_0; 1654 | output[0].imag = T65 + T64 + T68 + T71; 1655 | output[4 * count].imag = T68 + T71 - (T65 + T64); 1656 | output[6 * count].real = T7_0 - T18_0 - (T64 - T65); 1657 | output[2 * count].real = T7_0 - T18_0 + T64 - T65; 1658 | output[2 * count].imag = T30_0 - T41_0 + T71 - T68; 1659 | output[6 * count].imag = T71 - T68 - (T30_0 - T41_0); 1660 | stb_real_t T62 = (T56 - T53 - (T48_0 + T51_0)) * STB_KP707106781; 1661 | stb_real_t T75 = (T48_0 + T51_0 + T56 - T53) * STB_KP707106781; 1662 | output[7 * count].real = T43_0 + T46_0 - T62; 1663 | output[5 * count].imag = T76 + T77 - T75; 1664 | output[3 * count].real = T43_0 + T46_0 + T62; 1665 | output[count].imag = T75 + T76 + T77; 1666 | stb_real_t T58 = (T48_0 - T51_0 + T53 + T56) * STB_KP707106781; 1667 | stb_real_t T79 = (T48_0 - T51_0 - (T53 + T56)) * STB_KP707106781; 1668 | output[5 * count].real = T43_0 - T46_0 - T58; 1669 | output[7 * count].imag = T77 - T76 - T79; 1670 | output[count].real = T43_0 - T46_0 + T58; 1671 | output[3 * count].imag = T79 + T77 - T76; 1672 | ++m; 1673 | ++output; 1674 | tw += 7; 1675 | } 1676 | } 1677 | 1678 | void stb_recursive_mixed_radix_dit(const stb_fft_plan* plan, int stage, cmplx* in, cmplx* out, int sign) 1679 | { 1680 | const int radix = plan->stages.radix[stage]; 1681 | const int count = plan->stages.remainder[stage]; 1682 | cmplx* twiddles = plan->twiddles; 1683 | const int tw_offset = plan->stages.offsets[stage]; 1684 | cmplx* tw_sequential = &plan->twiddles_ordered[tw_offset]; 1685 | if (count == 1) { 1686 | for (int i = 0; i < radix; i++) { 1687 | out[i] = in[i * sign]; 1688 | } 1689 | } else { 1690 | const int cur_sign = sign * radix; 1691 | for (int i = 0; i < radix; ++i) { 1692 | stb_recursive_mixed_radix_dit(plan, stage + 1, &in[sign * i], &out[count * i], cur_sign); 1693 | } 1694 | } 1695 | switch (radix) { 1696 | case 2: 1697 | stb_radix_2_dit(tw_sequential, out, count); 1698 | break; 1699 | case 3: 1700 | stb_radix_3_dit(tw_sequential, out, count); 1701 | break; 1702 | case 4: 1703 | stb_radix_4_dit(tw_sequential, out, count); 1704 | break; 1705 | case 5: 1706 | stb_radix_5_dit(tw_sequential, out, count); 1707 | break; 1708 | case 6: 1709 | stb_radix_6_dit(tw_sequential, out, count); 1710 | break; 1711 | case 7: 1712 | stb_radix_7_dit(tw_sequential, out, count); 1713 | break; 1714 | case 8: 1715 | stb_radix_8_dit(tw_sequential, out, count); 1716 | break; 1717 | default: 1718 | stb_general_dit(twiddles, out, count, sign, radix, plan->N, 0); 1719 | break; 1720 | } 1721 | } 1722 | 1723 | void stb_recursive_mixed_radix_idit(const stb_fft_plan* plan, int stage, cmplx* in, cmplx* out, int sign) 1724 | { 1725 | const int radix = plan->stages.radix[stage]; 1726 | const int count = plan->stages.remainder[stage]; 1727 | cmplx* twiddles = plan->twiddles; 1728 | const int tw_offset = plan->stages.offsets[stage]; 1729 | cmplx* tw_sequential = &plan->twiddles_ordered[tw_offset]; 1730 | if (count == 1) { 1731 | for (int i = 0; i < radix; i++) { 1732 | out[i] = in[i * sign]; 1733 | } 1734 | } else { 1735 | const int cur_sign = sign * radix; 1736 | for (int i = 0; i < radix; ++i) { 1737 | stb_recursive_mixed_radix_idit(plan, stage + 1, &in[sign * i], &out[count * i], 1738 | cur_sign); 1739 | } 1740 | } 1741 | switch (radix) { 1742 | case 2: 1743 | stb_radix_2_idit(tw_sequential, out, count); 1744 | break; 1745 | case 3: 1746 | stb_radix_3_idit(tw_sequential, out, count); 1747 | break; 1748 | case 4: 1749 | stb_radix_4_idit(tw_sequential, out, count); 1750 | break; 1751 | case 5: 1752 | stb_radix_5_idit(tw_sequential, out, count); 1753 | break; 1754 | case 6: 1755 | stb_radix_6_idit(tw_sequential, out, count); 1756 | break; 1757 | case 7: 1758 | stb_radix_7_idit(tw_sequential, out, count); 1759 | break; 1760 | case 8: 1761 | stb_radix_8_idit(tw_sequential, out, count); 1762 | break; 1763 | default: 1764 | stb_general_dit(twiddles, out, count, sign, radix, plan->N, 1); 1765 | break; 1766 | } 1767 | } 1768 | 1769 | void stb_fft_exec(const stb_fft_plan* plan, cmplx* in, cmplx* out) 1770 | { 1771 | if (in == out) { 1772 | cmplx* buf = (cmplx*)calloc(plan->N, sizeof(cmplx)); 1773 | if (buf == NULL) 1774 | return; 1775 | stb_recursive_mixed_radix_dit(plan, 0, in, buf, 1); 1776 | memcpy(out, buf, sizeof(cmplx) * plan->N); 1777 | free(buf); 1778 | } else { 1779 | stb_recursive_mixed_radix_dit(plan, 0, in, out, 1); 1780 | } 1781 | } 1782 | 1783 | void stb_ifft_exec(const stb_fft_plan* plan, cmplx* in, cmplx* out) 1784 | { 1785 | if (in == out) { 1786 | cmplx* buf = (cmplx*)calloc(plan->N, sizeof(cmplx)); 1787 | if (buf == NULL) 1788 | return; 1789 | stb_recursive_mixed_radix_idit(plan, 0, in, buf, 1); 1790 | memcpy(out, buf, sizeof(cmplx) * plan->N); 1791 | free(buf); 1792 | } else { 1793 | stb_recursive_mixed_radix_idit(plan, 0, in, out, 1); 1794 | } 1795 | } 1796 | 1797 | void stb_fft_r2c_exec(stb_fft_real_plan* plan, const stb_real_t* input, cmplx* output) 1798 | { 1799 | int n = plan->half_plan->N; 1800 | stb_fft_exec(plan->half_plan, (cmplx*)input, plan->buffer); 1801 | cmplx tdc = plan->buffer[0]; 1802 | output[0].real = tdc.imag + tdc.real; 1803 | output[n].real = tdc.real - tdc.imag; 1804 | output[0].imag = 0.0; 1805 | output[n].imag = output[0].imag; 1806 | for (int c = 1; c <= n / 2; ++c) { 1807 | cmplx t = plan->buffer[n - c]; 1808 | t.imag = -t.imag; 1809 | stb_real_t r = (plan->twiddles[c - 1].real * (plan->buffer[c].real - t.real)) - (plan->twiddles[c - 1].imag * (plan->buffer[c].imag - t.imag)); 1810 | stb_real_t i = (plan->twiddles[c - 1].real * (plan->buffer[c].imag - t.imag)) + ((plan->buffer[c].real - t.real) * plan->twiddles[c - 1].imag); 1811 | output[c].real = (r + (t.real + plan->buffer[c].real)) * STB_KP5; 1812 | output[c].imag = (i + (t.imag + plan->buffer[c].imag)) * STB_KP5; 1813 | output[n - c].real = ((t.real + plan->buffer[c].real) - r) * STB_KP5; 1814 | output[n - c].imag = (i - (t.imag + plan->buffer[c].imag)) * STB_KP5; 1815 | } 1816 | } 1817 | 1818 | void stb_fft_c2r_exec(stb_fft_real_plan* plan, const cmplx* input, stb_real_t* output) 1819 | { 1820 | int n = plan->half_plan->N; 1821 | plan->buffer[0].real = input[n].real + input[0].real; 1822 | plan->buffer[0].imag = input[0].real - input[n].real; 1823 | for (int c = 1; c <= n / 2; ++c) { 1824 | cmplx t = input[n - c]; 1825 | t.imag = -t.imag; 1826 | stb_real_t r = (plan->twiddles[c - 1].real * (input[c].real - t.real)) + (plan->twiddles[c - 1].imag * (input[c].imag - t.imag)); 1827 | stb_real_t i = (plan->twiddles[c - 1].real * (input[c].imag - t.imag)) - ((input[c].real - t.real) * plan->twiddles[c - 1].imag); 1828 | plan->buffer[c].real = (r + t.real + input[c].real); 1829 | plan->buffer[c].imag = (i + t.imag + input[c].imag); 1830 | plan->buffer[n - c].real = (t.real + input[c].real - r); 1831 | plan->buffer[n - c].imag = (i - t.imag - input[c].imag); 1832 | } 1833 | stb_ifft_exec(plan->half_plan, plan->buffer, (cmplx*)output); 1834 | } 1835 | 1836 | void STB_FFT(cmplx* input, cmplx* output, int n) 1837 | { 1838 | if (n < 2) { 1839 | output[0] = input[0]; 1840 | return; 1841 | } 1842 | stb_fft_plan* plan = stb_fft_plan_dft_1d(n); 1843 | if (plan != NULL) { 1844 | stb_fft_exec(plan, input, output); 1845 | free(plan); 1846 | } 1847 | } 1848 | 1849 | void STB_IFFT(cmplx* input, cmplx* output, int n) 1850 | { 1851 | if (n < 2) { 1852 | output[0] = input[0]; 1853 | return; 1854 | } 1855 | stb_fft_plan* plan = stb_fft_plan_dft_1d(n); 1856 | if (plan != NULL) { 1857 | stb_ifft_exec(plan, input, output); 1858 | free(plan); 1859 | } 1860 | } 1861 | 1862 | void STB_FFT_R2C(stb_real_t* input, cmplx* output, int n) 1863 | { 1864 | if (n < 2) { 1865 | output[0].real = input[0]; 1866 | return; 1867 | } 1868 | stb_fft_real_plan* stb_fft_plan = stb_fft_real_plan_dft_1d(n); 1869 | if (stb_fft_plan != NULL) { 1870 | stb_fft_r2c_exec(stb_fft_plan, input, output); 1871 | free(stb_fft_plan); 1872 | } 1873 | } 1874 | 1875 | void STB_IFFT_C2R(cmplx* input, stb_real_t* output, int n) 1876 | { 1877 | if (n < 2) { 1878 | output[0] = input[0].real; 1879 | return; 1880 | } 1881 | stb_fft_real_plan* stb_fft_plan = stb_fft_real_plan_dft_1d(n); 1882 | if (stb_fft_plan != NULL) { 1883 | stb_fft_c2r_exec(stb_fft_plan, input, output); 1884 | free(stb_fft_plan); 1885 | } 1886 | } 1887 | 1888 | #endif 1889 | 1890 | // REVISION HISTORY 1891 | // v0.11 - 2018-12-28 1892 | // - Initial versioned release. 1893 | 1894 | /* 1895 | This is free and unencumbered software released into the public domain. 1896 | Anyone is free to copy, modify, publish, use, compile, sell, or 1897 | distribute this software, either in source code form or as a compiled 1898 | binary, for any purpose, commercial or non-commercial, and by any 1899 | means. 1900 | In jurisdictions that recognize copyright laws, the author or authors 1901 | of this software dedicate any and all copyright interest in the 1902 | software to the public domain. We make this dedication for the benefit 1903 | of the public at large and to the detriment of our heirs and 1904 | successors. We intend this dedication to be an overt act of 1905 | relinquishment in perpetuity of all present and future rights to this 1906 | software under copyright law. 1907 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1908 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1909 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 1910 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 1911 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1912 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 1913 | OTHER DEALINGS IN THE SOFTWARE. 1914 | For more information, please refer to 1915 | */ -------------------------------------------------------------------------------- /timing.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #if defined(__APPLE__) 5 | # include 6 | #elif defined(_WIN32) 7 | # define WIN32_LEAN_AND_MEAN 8 | 9 | # include 10 | 11 | #else // __linux 12 | 13 | # include 14 | 15 | # ifndef CLOCK_MONOTONIC //_RAW 16 | # define CLOCK_MONOTONIC CLOCK_REALTIME 17 | # endif 18 | #endif 19 | 20 | static 21 | uint64_t nanotimer() { 22 | static int ever = 0; 23 | #if defined(__APPLE__) 24 | static mach_timebase_info_data_t frequency; 25 | if (!ever) { 26 | if (mach_timebase_info(&frequency) != KERN_SUCCESS) { 27 | return 0; 28 | } 29 | ever = 1; 30 | } 31 | return (mach_absolute_time() * frequency.numer / frequency.denom); 32 | #elif defined(_WIN32) 33 | static LARGE_INTEGER frequency; 34 | if (!ever) { 35 | QueryPerformanceFrequency(&frequency); 36 | ever = 1; 37 | } 38 | LARGE_INTEGER t; 39 | QueryPerformanceCounter(&t); 40 | return (t.QuadPart * (uint64_t) 1e9) / frequency.QuadPart; 41 | #else // __linux 42 | struct timespec t; 43 | if (!ever) { 44 | if (clock_gettime(CLOCK_MONOTONIC, &t) != 0) { 45 | return 0; 46 | } 47 | ever = 1; 48 | } 49 | clock_gettime(CLOCK_MONOTONIC, &t); 50 | return (t.tv_sec * (uint64_t) 1e9) + t.tv_nsec; 51 | #endif 52 | } 53 | 54 | 55 | static double now() { 56 | static uint64_t epoch = 0; 57 | if (!epoch) { 58 | epoch = nanotimer(); 59 | } 60 | return (nanotimer() - epoch) / 1e9; 61 | }; 62 | 63 | static double calcElapsed(double start, double end) { 64 | double took = -start; 65 | return took + end; 66 | } --------------------------------------------------------------------------------