mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 04:47:35 +00:00
SoundPlayer: Use overlapping windows for bars visualization
For DSP reasons I can't explain myself (yet, sorry), short-time Fourier transform (STFT) is much more accurate and aesthetically pleasing when the windows that select the samples for STFT overlap. This implements that behavior by storing the previous samples and performing windowed FFT over both it as well as the current samples. This gives us 50% overlap between windows, a common standard that is nice to look at.
This commit is contained in:
parent
a5d95aa6e8
commit
21266f42f1
2 changed files with 13 additions and 4 deletions
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "BarsVisualizationWidget.h"
|
||||
#include <AK/Math.h>
|
||||
#include <AK/TypedTransfer.h>
|
||||
#include <LibDSP/FFT.h>
|
||||
#include <LibDSP/Window.h>
|
||||
#include <LibGUI/Event.h>
|
||||
|
@ -22,8 +23,14 @@ void BarsVisualizationWidget::render(GUI::PaintEvent& event, FixedArray<double>
|
|||
painter.add_clip_rect(event.rect());
|
||||
painter.fill_rect(frame_inner_rect(), Color::Black);
|
||||
|
||||
for (size_t i = 0; i < fft_size; i++)
|
||||
m_fft_samples[i] = samples[i] * m_fft_window[i];
|
||||
// First half of data is from previous iteration, second half is from now.
|
||||
// This gives us fully overlapping windows, which result in more accurate and visually appealing STFT.
|
||||
for (size_t i = 0; i < fft_size / 2; i++)
|
||||
m_fft_samples[i] = m_previous_samples[i] * m_fft_window[i];
|
||||
for (size_t i = 0; i < fft_size / 2; i++)
|
||||
m_fft_samples[i + fft_size / 2] = samples[i] * m_fft_window[i + fft_size / 2];
|
||||
|
||||
AK::TypedTransfer<double>::copy(m_previous_samples.data(), samples.data(), samples.size());
|
||||
|
||||
LibDSP::fft(m_fft_samples.span(), false);
|
||||
|
||||
|
@ -74,7 +81,8 @@ BarsVisualizationWidget::BarsVisualizationWidget()
|
|||
|
||||
m_fft_window = LibDSP::Window<double>::hann<fft_size>();
|
||||
|
||||
MUST(set_render_sample_count(fft_size));
|
||||
// As we use full-overlapping windows, the passed-in data is only half the size of one FFT operation.
|
||||
MUST(set_render_sample_count(fft_size / 2));
|
||||
}
|
||||
|
||||
void BarsVisualizationWidget::context_menu_event(GUI::ContextMenuEvent& event)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue