-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathFFTProcessor.h
More file actions
124 lines (113 loc) · 4.63 KB
/
FFTProcessor.h
File metadata and controls
124 lines (113 loc) · 4.63 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
#ifndef __FFT_PROCESSOR_H__
#define __FFT_PROCESSOR_H__
#include "SignalProcessor.h"
#include "Window.h"
template <class FrequencyDomainProcessor, size_t fft_size, size_t window_size>
class FFTProcessor : public SignalProcessor {
public:
FFTProcessor(FastFourierTransform* fft, FrequencyDomainProcessor* processor,
FloatArray timedomain, ComplexFloatArray freqdomain, FloatArray in_overlap,
FloatArray out_overlap, Window in_win, Window out_win)
: fft(fft)
, index(0)
, timedomain(timedomain)
, freqdomain(freqdomain)
, in_overlap(in_overlap)
, out_overlap(out_overlap)
, in_win(in_win)
, out_win(out_win)
, processor(processor) {
}
FrequencyDomainProcessor* getFrequencyDomainProcessor() {
return processor;
}
/**
* We don't support sample based processing in this class
**/
float process(float input) override {
return 0.0;
}
void process(FloatArray input, FloatArray output) override{
const size_t block_size = input.getSize();
// Insert twice to prepare contiguous copy of data when we reach buffer end
in_overlap.insert(input, index, block_size);
in_overlap.insert(input, (index + window_size) % (window_size * 2), block_size);
// When end is reach, we rewind to middle of the buffer
if (index >= window_size * 2 - block_size) {
index = window_size;
}
else {
index += block_size;
}
// Process data only when there's enough input to fill first window
if (index >= window_size) {
// FFT
in_win.apply(in_overlap.getData() + index - window_size, timedomain);
fft->fft(timedomain, freqdomain);
ComplexFloatArray bins = freqdomain.subArray(0, fft_size / 2);
// Time domain processing
processor->process(bins, bins);
// IFFT
fft->ifft(freqdomain, timedomain);
out_win.apply(timedomain);
// Overlap accumulation
const size_t out_index = index - window_size;
output.copyFrom(timedomain.subArray(0, block_size));
FloatArray t = out_overlap.subArray(out_index, block_size);
output.add(t);
t.setAll(0);
out_overlap
.subArray(out_index + block_size, window_size - out_index - block_size)
.add(timedomain.subArray(
block_size, window_size - out_index - block_size));
out_overlap.subArray(0, out_index)
.add(timedomain.subArray(window_size - out_index, out_index));
}
}
template <typename... Args>
static FFTProcessor* create(size_t block_size,
Window::WindowType in_win_type = Window::HannWindow,
Window::WindowType out_win_type = Window::HannWindow, Args&&... args) {
FrequencyDomainProcessor* processor =
FrequencyDomainProcessor::create(std::forward<Args>(args)...);
Window in_win = Window::create(in_win_type, window_size);
Window out_win = Window::create(out_win_type, window_size);
float norm[block_size];
memset(norm, 0, block_size * sizeof(float));
// Accumulate shifted multiplications of both windows as norm
for (size_t i = 0; i < window_size; i++) {
norm[i % block_size] += in_win[i] * out_win[i];
}
// Divide output window by the norm for every block size, compensating amplitude changes
float* t = out_win.getData();
for (size_t i = 0; i < window_size / block_size; i++) {
for (size_t j = 0; j < block_size; j++) {
*t++ /= norm[j];
}
}
return new FFTProcessor(FastFourierTransform::create(fft_size), processor,
FloatArray::create(fft_size), ComplexFloatArray::create(fft_size),
FloatArray::create(window_size * 2),
FloatArray::create(window_size), in_win, out_win);
}
static void destroy(FFTProcessor* fft) {
FloatArray::destroy(fft->timedomain);
ComplexFloatArray::destroy(fft->freqdomain);
FloatArray::destroy(fft->in_overlap);
FloatArray::destroy(fft->out_overlap);
Window::destroy(fft->in_win);
Window::destroy(fft->out_win);
FrequencyDomainProcessor::destroy(fft->processor);
FastFourierTransform::destroy(fft->fft);
delete fft;
}
protected:
size_t index;
FastFourierTransform* fft;
FloatArray timedomain;
ComplexFloatArray freqdomain;
Window in_win, out_win;
FloatArray in_overlap, out_overlap;
FrequencyDomainProcessor* processor;
};
#endif