-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdftt.h
More file actions
572 lines (503 loc) · 15.5 KB
/
dftt.h
File metadata and controls
572 lines (503 loc) · 15.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
#pragma once
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <complex.h>
#include <time.h>
#include <sndfile.h>
#include <float.h>
#define MAX_STR 999
#define MIN_STR 200
#define WELCOME_STR "\nDiscrete Fourier Transform Tool (DFTT). Created by Yiannis Michael (ymich9963), 2025.\n\nUse '--version' for version information, or '--help' for the list of options.\n\nBasic usage 'dftt <Input audio file or CSV file or CSV string> [options]. For list of options use '--help'.\n"
#define VERSION_STR "\nDFTT v0.5.3.\n\n"
#define SND_MAJOR_FORMAT_NUM 27
#define SND_SUBTYPE_NUM 36
#define REAL_DATA_INDEX 0
#define IMAG_DATA_INDEX 1
#define FREQ_BINS_INDEX 2
/* Check macros */
/* Check response from sscanf */
#define CHECK_RES(x) ({ if (!(x)) { \
fprintf(stderr, "Argument entered was wrong...\n"); \
return 1; \
} \
})
/* Check if an error occured to exit program */
#define CHECK_ERR(x) ({ if ((x)) { \
exit(EXIT_FAILURE); \
} \
})
/* Check if a function returns failure */
#define CHECK_RET(x) ({ if ((x)) { \
return 1; \
} \
})
/* Check the quiet flag and output a simple sting */
#define STATUS(x, string) ({ if ((!x)) { \
printf(string); \
} \
})
/* Check string length */
#define CHECK_STR_LEN(x) ({ if (strlen((x)) > MAX_STR) { \
fprintf(stderr, "Argument string length was too large. Max is %d.\n", MAX_STR); \
return 1; \
} \
})
typedef struct DFTT_Config dftt_config_t;
typedef struct DFTT_Config {
/* Buffers */
char ibuff[MAX_STR];
char ofile[MAX_STR];
/* Audio file vars */
uint8_t channels;
size_t total_samples;
size_t detected_samples;
size_t sampling_freq;
/* Timers */
struct timespec start_time;
struct timespec end_time;
/* Format specifier vars */
char format[9]; // Format string for the output precision
uint8_t precision;
/* Flags */
uint8_t info_flag;
uint8_t fft_flag;
uint8_t timer_flag;
uint8_t input_flag;
uint8_t quiet_flag;
uint8_t pow_flag;
uint8_t norm_flag;
uint8_t bins_flag;
uint8_t headers_flag;
uint8_t half_flag;
uint8_t shift_flag;
/* Function pointers */
int (*inp)(dftt_config_t* dftt_conf, double** x);
void (*dft)(dftt_config_t* dftt_conf, double _Complex* X, double* x_mono);
int (*outp)(dftt_config_t* dftt_conf, double** X);
} dftt_config_t;
/**
* @brief Set default values to make sure DFTT runs correctly.
*
* @param dftt_conf DFTT Config struct.
*/
void set_defaults(dftt_config_t* dftt_conf);
/**
* @brief Get the options specified from the CLI.
*
* @param argc Option count.
* @param argv Option string array.
* @param dftt_conf DFTT Config struct.
* @return Success or failure.
*/
int get_options(int argc, char** argv, dftt_config_t* dftt_conf);
/**
* @brief Read the input and decide how to treat it.
*
* @param dftt_conf DFTT Config struct.
* @return Success or failure.
*/
int read_input(dftt_config_t* dftt_conf);
/**
* @brief Select the output format.
*
* @param dftt_conf DFTT Config struct.
* @param strval Option value.
* @return Success or failure.
*/
int select_output_format(dftt_config_t* dftt_conf, char* strval);
/**
* @brief Read the input as an audio file and place it into a new buffer.
*
* @param dftt_conf DFTT Config struct.
* @param x Pointer to data buffer.
* @return Success or failure.
*/
int read_audio_file_input(dftt_config_t* dftt_conf, double** x);
/**
* @brief Open the audio file.
*
* @param file Pointer to SNDFILE pointer.
* @param sf_info SF_INFO type from libsndfile.
* @param ibuff Input buffer of size MAX_STR
* @return Success or failure.
*/
int open_audio_file(SNDFILE** file, SF_INFO* sf_info, char* ibuff);
/**
* @brief Get the data from the audio file.
*
* @param file SNDFILE pointer.
* @param sf_info SF_INFO type from libsndfile.
* @param x Pointer to data buffer.
* @return Success or failure.
*/
int get_audio_file_data(SNDFILE* file, SF_INFO* sf_info, double** x);
/**
* @brief Output some info about the inputted audio file.
*
* @param dftt_conf DFTT Config struct.
* @param sf_info SF_INFO pointer.
* @return Success or failure.
*/
int output_audio_file_info(dftt_config_t* dftt_conf, SF_INFO* sf_info);
/**
* @brief Get the SNDFILE major format string. Same as descriptions given in the documentation.
*
* @param sf_info Pointer to SF_INFO variable containing file information.
* @return Major format string
*/
const char* get_sndfile_major_format(SF_INFO* sf_info);
/**
* @brief Get the SNDFILE subtype string. Same as subtypes given in the documentation.
*
* @param sf_info Pointer to SF_INFO variable containing file information.
* @return Subtype string.
*/
const char* get_sndfile_subtype(SF_INFO* sf_info);
/**
* @brief Check the string if is in CSV format.
*
* @param ibuff Input buffer.
* @return Success or failure.
*/
int check_csv_string(char* ibuff);
/**
* @brief Check the extension in the input buffer if it can be read like a CSV.
*
* @param ibuff Input buffer.
* @return Success or failure.
*/
int check_csv_extension(char* ibuff);
/**
* @brief Read the input as a CSV file or CSV string.
*
* @param dftt_conf DFTT Config struct.
* @param x Pointer to data buffer.
* @return Success or failure.
*/
int read_csv_string_file_input(dftt_config_t* dftt_conf, double** x);
/**
* @brief Read the input as a CSV file or CSV string.
*
* @param dftt_conf DFTT Config struct.
* @param x Pointer to data buffer.
* @return Success or failure.
*/
int read_csv_string_file_input(dftt_config_t* dftt_conf, double** x);
/**
* @brief Open the input file as a CSV file. If the function fails it means it's a CSV string.
*
* @param file Pointer to FILE pointer.
* @param ibuff Input buffer.
* @return Success or failure.
*/
int open_csv_file(FILE** file, char* ibuff);
/**
* @brief Read the data from the CSV file.
*
* @param file FILE pointer.
* @param data_string Pointer to a string buffer.
* @return Success or failure.
*/
int read_csv_file_data(FILE* file, char** data_string);
/**
* @brief Get the data from a CSV string and store it in a buffer.
*
* @param data_string String containing the data.
* @param x Pointer to buffer to store the data.
* @param detected_samples Variable to store the detected samples in the string.
* @return Success or failure.
*/
int get_data_from_string(char* data_string, double** x, size_t* detected_samples);
/**
* @brief Output some info about the input.
*
* @param dftt_conf DFTT Config struct.
* @return Success or failure.
*/
int output_input_info(dftt_config_t* dftt_conf);
/**
* @brief Mix the data to mono.
*
* @param sf_info Pointer to SF_INFO struct.
* @param x Data buffer.
* @param x_mono Pointer to store the processed data buffer.
*/
void mix2mono(SF_INFO* sf_info, double* x, double** x_mono);
/**
* @brief Select the FFT algorithm based on the input string.
*
* @param dftt_conf DFTT Config struct.
* @param strval Option value.
* @return Success or failure.
*/
int select_fft_algo(dftt_config_t* dftt_conf, char* strval);
/**
* @brief Check if the timer should be started.
*
* @param dftt_conf DFTT Config struct.
*/
void check_timer_start(dftt_config_t* dftt_conf);
/**
* @brief Append the input array with zeros.
*
* @param arr Pointer to data buffer.
* @param new_size New size of the array.
* @param old_size Old size of the array.
* @return Success or failure.
*/
int zero_pad_array(double** arr, size_t new_size, size_t old_size);
/**
* @brief Truncate the input array.
*
* @param arr Pointer to data buffer.
* @param new_size New size of the array.
* @return Success or failure.
*/
int truncate_array(double** arr, size_t new_size);
/**
* @brief Find the next power of two of a number.
*
* @param size Pointer to the number to find the next power of two for.
*/
void nextpow2(size_t* num);
/**
* @brief Set the size of the arrays and corresponding variables before executing any DFT.
*
* @param dftt_conf DFTT Config struct.
* @param X Pointer to complex data buffer.
* @param x Pointer to input data buffer.
* @return Success or failure.
*/
int set_transform_size(dftt_config_t* dftt_conf, double _Complex** X, double** x);
/**
* @brief Generate the index array containing bit-reversed positions that will be used at indexes.
*
* @param index_arr Array containing the index data.
* @param n Size of the index array.
*/
void index_bit_reversal(size_t* index_arr, size_t n);
/**
* @brief Reorder data to the indexes in the index array.
*
* @param index_arr Array containing the index data.
* @param data_arr Data buffer of type double.
* @param data_size Size of data buffer.
*/
void reorder_data_dit(size_t* index_arr, double* data_arr, size_t data_size);
/**
* @brief Reorder data to the indexes in the index array.
*
* @param index_arr Array containing the index data.
* @param data_arr Data buffer of type complex.
* @param data_size Size of data buffer.
*/
void reorder_data_dif(size_t* index_arr, double _Complex* data_arr, size_t data_size);
/**
* @brief Convert a buffer of type double to type _Complex.
*
* @param x Buffer of type double.
* @param X_complex Buffer of type _Complex.
* @param size Size of the buffers.
*/
void convert_to_complex(double* x, double _Complex* X_complex, size_t size);
/**
* @brief Get the twiddle factor based on the indexes.
*
* @param nk Index of current sequence.
* @param N Size of current sequence.
* @return Complex double.
*/
double _Complex get_twiddle_factor(size_t nk, size_t N);
/**
* @brief DFT.
*
* @param dftt_conf DFTT Config struct.
* @param X Data buffer of type complex double.
* @param x Data buffer.
*/
void dft(dftt_config_t* dftt_conf, double _Complex* X, double* x);
/**
* @brief Execute butterfly for the Discrete In Time FFT.
*
* @param X Data buffer of type complex double to store the result.
* @param X_copy Complex copy of the input.
* @param k Size of the data buffer.
*/
void butterfly_dit(double _Complex* X, double _Complex* X_copy, size_t k);
/**
* @brief Execute butterfly for the Discrete In Frequency FFT.
*
* @param X Data buffer of type double to store the result.
* @param X_copy Complex copy of the input.
* @param k Size of the data buffer.
*/
void butterfly_dif(double _Complex* X, double _Complex* X_copy, size_t k);
/**
* @brief Execute FFT Radix-2 Decimation In Time.
*
* @param dftt_conf DFTT Config struct.
* @param X Data buffer of type complex double.
* @param x Data buffer.
*/
void fft_radix2_dit(dftt_config_t* dftt_conf, double _Complex* X, double* x);
/**
* @brief Execute FFT Radix-2 Decimation In Frequency.
*
* @param dftt_conf DFTT Config struct.
* @param X Data buffer of type complex double.
* @param x Data buffer.
*/
void fft_radix2_dif(dftt_config_t* dftt_conf, double _Complex* X, double* x);
/**
* @brief Parse the complex data buffer into a 3D array which contains Real, Imaginary, and Frequency Bins (RIB). Required to centralise the data for outputing.
*
* @param X Complex data buffer
* @param X_RIB Pointer to data buffer containing the RIB data.
* @param size Size of the data buffer.
*/
void parse_complex_buff_to_RIB(double _Complex* X, double*** X_RIB, size_t size);
/**
* @brief Get a buffer containing the frequency bin values.
*
* @param X_bins Data buffer to store the bin values.
* @param f_s Sampling frequency.
* @param size Size of the data buffer that will store the values.
* @return Success or failure.
*/
int get_freq_bins(double* X_bins, size_t f_s, size_t size);
/**
* @brief Set the precision to be used when outputing the data.
*
* @param format Format string.
* @param precision Precision amount.
*/
void set_precision_format(char format[9], uint8_t precision);
/**
* @brief Get the power spectrum of the data, Gets stored in the Real part of the RIB array.
*
* @param X_real Real part of data.
* @param X_imag Imaginary part of data.
* @param size Size of data.
*/
void get_pow_spectrum(double* X_real, double* X_imag, size_t size);
/**
* @brief Normalise the data. Only used in the power output.
*
* @param x Data buffer.
* @param size Size of data buffer.
*/
void normalise_data(double* x, size_t size);
/**
* @brief Shift the data so that it's centered around 0.
*
* @param X_RIB RIB data buffer.
* @param size Size of data buffer.
*/
void fft_shift(double** X_RIB, size_t size);
/**
* @brief Prepare the data to be outputed. Set the precision, get the power spectrum, get the frequency bins, FFT-shift the data, normalise, or output only half.
*
* @param dftt_conf DFTT Config struct.
* @param X_RIB RIB data buffer.
*/
void prep_outp(dftt_config_t* dftt_conf, double** X_RIB);
/**
* @brief Get the date/time string to be used in the file name.
*
* @return Date/time string in ddmmyyHHMMSS format.
*/
char* get_datetime_string();
/**
* @brief Generate the output file name based on the input file name and the current date/time.
*
* @param ofile Output file name.
* @param ifile Input file name.
* @param input_flag Flag previously set that specifies the type of input.
*/
void generate_file_name(char* ofile, char* ibuff, uint8_t input_flag);
/**
* @brief Print the frequency bin along with a separator.
*
* @param file File buffer.
* @param freq_bin Frequency bin to print.
* @param bins_flag Flag to check if it will be printed.
* @param separator Separator.
*/
void print_freq_bin(FILE* file, double freq_bin, uint8_t bins_flag, char separator[4]);
/**
* @brief Check if the value is a negative zero and if it is set it as a positive zero.
*
* @param x Value to check.
*/
void check_neg_zero(double* x);
/**
* @brief Output column headings. Used in CSV outputs.
*
* @param file FILE buffer.
* @param bins_flag Flag to check if bins are outputed.
* @param pow_flag Flag to check if power spectrum is outputed.
* @param pow_flag Flag to output column headers.
*
* @return Byte containing flag values.
*/
uint8_t print_csv_headings(FILE* file, uint8_t headers_flag, uint8_t pow_flag, uint8_t bins_flag);
/**
* @brief Output to stdout in columns.
*
* @param dftt_conf DFTT Config struct.
* @param X_RIB RIB data buffer.
* @return Success or failure.
*/
int output_stdout(dftt_config_t* dftt_conf, double** X_RIB);
/**
* @brief Output to stdout as CSV. Values are separated with ',' and each entry is separated by ';'.
*
* @param dftt_conf DFTT Config struct.
* @param X_RIB RIB data buffer.
* @return Success or failure.
*/
int output_stdout_csv(dftt_config_t* dftt_conf, double** X_RIB);
/**
* @brief Output to a file buffer as columns.
*
* @param dftt_conf DFTT Config struct.
* @param X_RIB RIB data buffer.
* @return Success or failure.
*/
int output_file_columns(dftt_config_t* dftt_conf, double** X_RIB);
/**
* @brief Output to a file buffer as CSV.
*
* @param dftt_conf DFTT Config struct.
* @param X_RIB RIB data buffer.
* @return Success or failure.
*/
int output_file_csv(dftt_config_t* dftt_conf, double** X_RIB);
/**
* @brief Output to a file buffer as a hex dump.
*
* @param dftt_conf DFTT Config struct.
* @param X_RIB RIB data buffer.
* @return Success or failure.
*/
int output_file_hex_dump(dftt_config_t* dftt_conf, double** X_RIB);
/**
* @brief Output to a file buffer as a C-style array.
*
* @param dftt_conf DFTT Config struct.
* @param X_RIB RIB data buffer.
* @return Success or failure.
*/
int output_file_c_array(dftt_config_t* dftt_conf, double** X_RIB);
/**
* @brief Check if the timer should be stopped and outputed.
*
* @param dftt_conf DFTT Config struct.
*/
void check_timer_end_output(dftt_config_t* dftt_conf);
/**
* @brief Output the '--help' option.
* @return Success or failure.
*/
int output_help();