Skip to content

Commit 00dd8f8

Browse files
kleinesfilmroellchenawesomekling
authored andcommitted
LibDSP: Generalize & improve FFT
Several related improvements to our Fast Fourier Transform implementation: - FFT now operates on spans, allowing it to use many more container types other than Vector. It's intended anyways that FFT transmutes the input data. - FFT is now constexpr, moving the implementation to the header and removing the cpp file. This means that if we have static collections of samples, we can transform them at compile time. - sample_data.data() weirdness is now gone.
1 parent 428d4ae commit 00dd8f8

File tree

4 files changed

+36
-66
lines changed

4 files changed

+36
-66
lines changed

Userland/Applications/SoundPlayer/BarsVisualizationWidget.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ void BarsVisualizationWidget::paint_event(GUI::PaintEvent& event)
2626
if (m_sample_buffer.is_empty())
2727
return;
2828

29-
LibDSP::fft(m_sample_buffer, false);
29+
LibDSP::fft(m_sample_buffer.span(), false);
3030
double max = AK::sqrt(m_sample_count * 2.);
3131

3232
double freq_bin = m_samplerate / (double)m_sample_count;

Userland/Libraries/LibDSP/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ set(SOURCES
33
Track.cpp
44
Effects.cpp
55
Synthesizers.cpp
6-
FFT.cpp
76
)
87

98
serenity_lib(LibDSP dsp)

Userland/Libraries/LibDSP/FFT.cpp

Lines changed: 0 additions & 62 deletions
This file was deleted.

Userland/Libraries/LibDSP/FFT.h

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,43 @@
77
#pragma once
88

99
#include <AK/Complex.h>
10-
#include <AK/Vector.h>
10+
#include <AK/Math.h>
11+
#include <AK/Span.h>
1112

1213
namespace LibDSP {
1314

14-
void fft(Vector<Complex<double>>& sample_data, bool invert = false);
15+
constexpr void fft(Span<Complex<double>> sample_data, bool invert = false)
16+
{
17+
int n = sample_data.size();
18+
19+
for (int i = 1, j = 0; i < n; i++) {
20+
int bit = n >> 1;
21+
for (; j & bit; bit >>= 1)
22+
j ^= bit;
23+
j ^= bit;
24+
25+
if (i < j)
26+
swap(sample_data[i], sample_data[j]);
27+
}
28+
29+
for (int len = 2; len <= n; len <<= 1) {
30+
double ang = 2 * AK::Pi<double> / len * (invert ? -1 : 1);
31+
Complex<double> wlen(AK::cos(ang), AK::sin(ang));
32+
for (int i = 0; i < n; i += len) {
33+
Complex<double> w = { 1., 0. };
34+
for (int j = 0; j < len / 2; j++) {
35+
Complex<double> u = sample_data[i + j], v = sample_data[i + j + len / 2] * w;
36+
sample_data[i + j] = u + v;
37+
sample_data[i + j + len / 2] = u - v;
38+
w *= wlen;
39+
}
40+
}
41+
}
42+
43+
if (invert) {
44+
for (int i = 0; i < n; i++)
45+
sample_data[i] /= n;
46+
}
47+
}
1548

1649
}

0 commit comments

Comments
 (0)