Krotos Modules 3
Loading...
Searching...
No Matches
FFTConvolver.cpp
Go to the documentation of this file.
1// ==================================================================================
2// Copyright (c) 2017 HiFi-LoFi
3//
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8// copies of the Software, and to permit persons to whom the Software is furnished
9// to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
19// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20// ==================================================================================
21#include <cassert>
22#include <cmath>
23
24#if defined(FFTCONVOLVER_USE_SSE)
25#include <xmmintrin.h>
26#endif
27
28namespace fftconvolver
29{
30
32 : _blockSize(0), _segSize(0), _segCount(0), _fftComplexSize(0), _segments(), _segmentsIR(), _fftBuffer(),
33 _fft(), _preMultiplied(), _conv(), _overlap(), _current(0), _inputBuffer(), _inputBufferFill(0)
34 {
35 }
36
38
40 {
41 for (size_t i = 0; i < _segCount; ++i)
42 {
43 delete _segments[i];
44 delete _segmentsIR[i];
45 }
46
47 _blockSize = 0;
48 _segSize = 0;
49 _segCount = 0;
51 _segments.clear();
52 _segmentsIR.clear();
54 _fft.init(0);
56 _conv.clear();
58 _current = 0;
61 }
62
63 bool FFTConvolver::init(size_t blockSize, const Sample* ir, size_t irLen)
64 {
65 reset();
66
67 if (blockSize == 0)
68 {
69 return false;
70 }
71
72 // Ignore zeros at the end of the impulse response because they only waste computation time
73 while (irLen > 0 && ::fabs(ir[irLen - 1]) < 0.000001f)
74 {
75 --irLen;
76 }
77
78 if (irLen == 0)
79 {
80 return true;
81 }
82
83 _blockSize = NextPowerOf2(blockSize);
84 _segSize = 2 * _blockSize;
85 _segCount = static_cast<size_t>(::ceil(static_cast<float>(irLen) / static_cast<float>(_blockSize)));
87
88 // FFT
91
92 // Prepare segments
93 for (size_t i = 0; i < _segCount; ++i)
94 {
96 }
97
98 // Prepare IR
99 for (size_t i = 0; i < _segCount; ++i)
100 {
102 const size_t remaining = irLen - (i * _blockSize);
103 const size_t sizeCopy = (remaining >= _blockSize) ? _blockSize : remaining;
104 CopyAndPad(_fftBuffer, &ir[i * _blockSize], sizeCopy);
105 _fft.fft(_fftBuffer.data(), segment->re(), segment->im());
106 _segmentsIR.push_back(segment);
107 }
108
109 // Prepare convolution buffers
113
114 // Prepare input buffer
117
118 // Reset current position
119 _current = 0;
120
121 return true;
122 }
123
124 void FFTConvolver::process(const Sample* input, Sample* output, size_t len)
125 {
126 if (_segCount == 0)
127 {
128 ::memset(output, 0, len * sizeof(Sample));
129 return;
130 }
131
132 size_t processed = 0;
133 while (processed < len)
134 {
135 const bool inputBufferWasEmpty = (_inputBufferFill == 0);
136 const size_t processing = std::min(len - processed, _blockSize - _inputBufferFill);
137 const size_t inputBufferPos = _inputBufferFill;
138 ::memcpy(_inputBuffer.data() + inputBufferPos, input + processed, processing * sizeof(Sample));
139
140 // Forward FFT
143
144 // Complex multiplication
145 if (inputBufferWasEmpty)
146 {
148 for (size_t i = 1; i < _segCount; ++i)
149 {
150 const size_t indexIr = i;
151 const size_t indexAudio = (_current + i) % _segCount;
153 }
154 }
157
158 // Backward FFT
160
161 // Add overlap
162 Sum(output + processed, _fftBuffer.data() + inputBufferPos, _overlap.data() + inputBufferPos, processing);
163
164 // Input buffer full => Next block
165 _inputBufferFill += processing;
167 {
168 // Input buffer is empty again now
171
172 // Save the overlap
173 ::memcpy(_overlap.data(), _fftBuffer.data() + _blockSize, _blockSize * sizeof(Sample));
174
175 // Update current segment
176 _current = (_current > 0) ? (_current - 1) : (_segCount - 1);
177 }
178
179 processed += processing;
180 }
181 }
182
183} // End of namespace fftconvolver
void init(size_t size)
Initializes the FFT object.
Definition AudioFFT.cpp:984
void fft(const float *data, float *re, float *im)
Performs the forward FFT.
Definition AudioFFT.cpp:990
void ifft(float *data, const float *re, const float *im)
Performs the inverse FFT.
Definition AudioFFT.cpp:992
static size_t ComplexSize(size_t size)
Calculates the necessary size of the real/imaginary complex arrays.
Definition AudioFFT.cpp:994
T * data()
Definition Utilities.h:117
void setZero()
Definition Utilities.h:92
void resize(size_t size)
Definition Utilities.h:74
void clear()
Definition Utilities.h:67
size_t _current
Definition FFTConvolver.h:83
size_t _segSize
Definition FFTConvolver.h:73
size_t _inputBufferFill
Definition FFTConvolver.h:85
SplitComplex _conv
Definition FFTConvolver.h:81
SplitComplex _preMultiplied
Definition FFTConvolver.h:80
void reset()
Resets the convolver and discards the set impulse response.
Definition FFTConvolver.cpp:39
std::vector< SplitComplex * > _segments
Definition FFTConvolver.h:76
size_t _fftComplexSize
Definition FFTConvolver.h:75
SampleBuffer _fftBuffer
Definition FFTConvolver.h:78
size_t _segCount
Definition FFTConvolver.h:74
void process(const Sample *input, Sample *output, size_t len)
Convolves the the given input samples and immediately outputs the result.
Definition FFTConvolver.cpp:124
audiofft::AudioFFT _fft
Definition FFTConvolver.h:79
SampleBuffer _overlap
Definition FFTConvolver.h:82
virtual ~FFTConvolver()
Definition FFTConvolver.cpp:37
SampleBuffer _inputBuffer
Definition FFTConvolver.h:84
bool init(size_t blockSize, const Sample *ir, size_t irLen)
Initializes the convolver.
Definition FFTConvolver.cpp:63
FFTConvolver()
Definition FFTConvolver.cpp:31
std::vector< SplitComplex * > _segmentsIR
Definition FFTConvolver.h:77
size_t _blockSize
Definition FFTConvolver.h:72
Buffer for split-complex representation of FFT results.
Definition Utilities.h:173
void setZero()
Definition Utilities.h:193
Sample * im()
Definition Utilities.h:209
void clear()
Definition Utilities.h:179
void copyFrom(const SplitComplex &other)
Definition Utilities.h:199
void resize(size_t newSize)
Definition Utilities.h:186
Sample * re()
Definition Utilities.h:205
Definition FFTConvolver.cpp:29
float Sample
Type of one sample.
Definition Utilities.h:157
T NextPowerOf2(const T &val)
Returns the next power of 2 of a given number.
Definition Utilities.h:230
void ComplexMultiplyAccumulate(SplitComplex &result, const SplitComplex &a, const SplitComplex &b)
Adds the complex product of two split-complex buffers to a result buffer.
Definition Utilities.cpp:53
void CopyAndPad(Buffer< T > &dest, const T *src, size_t srcSize)
Copies a source array into a destination buffer and pads the destination buffer with zeros.
Definition Utilities.h:256
void Sum(Sample *FFTCONVOLVER_RESTRICT result, const Sample *FFTCONVOLVER_RESTRICT a, const Sample *FFTCONVOLVER_RESTRICT b, size_t len)
Sums two given sample arrays.
Definition Utilities.cpp:36