mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 08:37:45 +00:00
SoundPlayer: Implement logarithmic spectrum display
Now that we have y-axis (gain) logarithmic display, we should also have x-axis (frequency) logarithmic display; that's how our ears work. This can be turned off with an option, but it generally looks much nicer.
This commit is contained in:
parent
9f856f3e45
commit
d2510d0caa
2 changed files with 33 additions and 8 deletions
|
@ -36,14 +36,31 @@ void BarsVisualizationWidget::render(GUI::PaintEvent& event, FixedArray<double>
|
||||||
|
|
||||||
Array<double, bar_count> groups {};
|
Array<double, bar_count> groups {};
|
||||||
|
|
||||||
for (size_t i = 0; i < fft_size / 2; i += values_per_bar) {
|
if (m_logarithmic_spectrum) {
|
||||||
double const magnitude = m_fft_samples[i].magnitude();
|
auto const log_bar_size = static_cast<double>(bar_count) / AK::log2(fft_size);
|
||||||
groups[i / values_per_bar] = magnitude;
|
|
||||||
for (size_t j = 0; j < values_per_bar; j++) {
|
for (size_t i = 0; i < bar_count; ++i) {
|
||||||
double const magnitude = m_fft_samples[i + j].magnitude();
|
auto const bar_start = i == 0 ? 0 : static_cast<size_t>(floor(AK::pow(2., static_cast<double>(i) / log_bar_size)));
|
||||||
groups[i / values_per_bar] += magnitude;
|
auto const bar_end = clamp(static_cast<size_t>(floor(AK::pow(2., static_cast<double>(i + 1) / log_bar_size))), bar_start + 1, cutoff);
|
||||||
|
auto const values_in_bar = bar_end - bar_start;
|
||||||
|
|
||||||
|
for (size_t sample_index = bar_start; sample_index < bar_start + values_in_bar; sample_index++) {
|
||||||
|
double const magnitude = m_fft_samples[sample_index].magnitude();
|
||||||
|
groups[i] += magnitude;
|
||||||
|
}
|
||||||
|
groups[i] /= static_cast<double>(values_in_bar);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
static constexpr size_t values_per_bar = (fft_size / 2) / bar_count;
|
||||||
|
for (size_t i = 0; i < fft_size / 2; i += values_per_bar) {
|
||||||
|
double const magnitude = m_fft_samples[i].magnitude();
|
||||||
|
groups[i / values_per_bar] = magnitude;
|
||||||
|
for (size_t j = 0; j < values_per_bar; j++) {
|
||||||
|
double const magnitude = m_fft_samples[i + j].magnitude();
|
||||||
|
groups[i / values_per_bar] += magnitude;
|
||||||
|
}
|
||||||
|
groups[i / values_per_bar] /= values_per_bar;
|
||||||
}
|
}
|
||||||
groups[i / values_per_bar] /= values_per_bar;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double const max_peak_value = AK::sqrt(static_cast<double>(fft_size * 2));
|
double const max_peak_value = AK::sqrt(static_cast<double>(fft_size * 2));
|
||||||
|
@ -71,6 +88,7 @@ void BarsVisualizationWidget::render(GUI::PaintEvent& event, FixedArray<double>
|
||||||
BarsVisualizationWidget::BarsVisualizationWidget()
|
BarsVisualizationWidget::BarsVisualizationWidget()
|
||||||
: m_is_using_last(false)
|
: m_is_using_last(false)
|
||||||
, m_adjust_frequencies(true)
|
, m_adjust_frequencies(true)
|
||||||
|
, m_logarithmic_spectrum(true)
|
||||||
{
|
{
|
||||||
m_context_menu = GUI::Menu::construct();
|
m_context_menu = GUI::Menu::construct();
|
||||||
auto frequency_energy_action = GUI::Action::create_checkable("Adjust frequency energy (for aesthetics)", [&](GUI::Action& action) {
|
auto frequency_energy_action = GUI::Action::create_checkable("Adjust frequency energy (for aesthetics)", [&](GUI::Action& action) {
|
||||||
|
@ -78,6 +96,11 @@ BarsVisualizationWidget::BarsVisualizationWidget()
|
||||||
});
|
});
|
||||||
frequency_energy_action->set_checked(true);
|
frequency_energy_action->set_checked(true);
|
||||||
m_context_menu->add_action(frequency_energy_action);
|
m_context_menu->add_action(frequency_energy_action);
|
||||||
|
auto logarithmic_spectrum_action = GUI::Action::create_checkable("Scale spectrum logarithmically", [&](GUI::Action& action) {
|
||||||
|
m_logarithmic_spectrum = action.is_checked();
|
||||||
|
});
|
||||||
|
logarithmic_spectrum_action->set_checked(true);
|
||||||
|
m_context_menu->add_action(logarithmic_spectrum_action);
|
||||||
|
|
||||||
m_fft_window = LibDSP::Window<double>::hann<fft_size>();
|
m_fft_window = LibDSP::Window<double>::hann<fft_size>();
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,8 @@ private:
|
||||||
|
|
||||||
static constexpr size_t fft_size = 512;
|
static constexpr size_t fft_size = 512;
|
||||||
static constexpr size_t bar_count = 64;
|
static constexpr size_t bar_count = 64;
|
||||||
static constexpr size_t values_per_bar = (fft_size / 2) / bar_count;
|
// Things become weird near the Nyquist limit. Just don't use that FFT data.
|
||||||
|
static constexpr size_t cutoff = fft_size - 32;
|
||||||
|
|
||||||
Array<Complex<double>, fft_size> m_fft_samples {};
|
Array<Complex<double>, fft_size> m_fft_samples {};
|
||||||
Array<double, fft_size> m_fft_window {};
|
Array<double, fft_size> m_fft_window {};
|
||||||
|
@ -36,5 +37,6 @@ private:
|
||||||
Array<int, bar_count> m_gfx_falling_bars {};
|
Array<int, bar_count> m_gfx_falling_bars {};
|
||||||
bool m_is_using_last;
|
bool m_is_using_last;
|
||||||
bool m_adjust_frequencies;
|
bool m_adjust_frequencies;
|
||||||
|
bool m_logarithmic_spectrum;
|
||||||
RefPtr<GUI::Menu> m_context_menu;
|
RefPtr<GUI::Menu> m_context_menu;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue