mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 21:07:34 +00:00
LibAudio+LibDSP: Switch samples to 32-bit float instead of 64-bit float
This has been overkill from the start, and it has been bugging me for a long time. With this change, we're probably a bit slower on most platforms but save huge amounts of space with all in-memory sample datastructures.
This commit is contained in:
parent
39c0f31009
commit
19a4b820c4
16 changed files with 329 additions and 329 deletions
|
@ -19,7 +19,7 @@ static FixedArray<Audio::Sample> music_samples_to_buffer(Vector<Music::Sample>&
|
|||
{
|
||||
FixedArray<Audio::Sample> samples = MUST(FixedArray<Audio::Sample>::try_create(music_samples.size()));
|
||||
for (size_t i = 0; i < music_samples.size(); ++i)
|
||||
samples[i] = { static_cast<double>(music_samples[i].left) / AK::NumericLimits<i16>::max(), static_cast<double>(music_samples[i].right) / AK::NumericLimits<i16>::max() };
|
||||
samples[i] = { static_cast<float>(music_samples[i].left) / AK::NumericLimits<i16>::max(), static_cast<float>(music_samples[i].right) / AK::NumericLimits<i16>::max() };
|
||||
|
||||
return samples;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ public:
|
|||
void start_new_file(StringView) override;
|
||||
|
||||
private:
|
||||
void render(GUI::PaintEvent&, FixedArray<double> const&) override { }
|
||||
void render(GUI::PaintEvent&, FixedArray<float> const&) override { }
|
||||
void paint_event(GUI::PaintEvent&) override;
|
||||
AlbumCoverVisualizationWidget() = default;
|
||||
ErrorOr<NonnullRefPtr<Gfx::Bitmap>> get_album_cover(StringView const filename);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <LibGUI/Painter.h>
|
||||
#include <LibGUI/Window.h>
|
||||
|
||||
void BarsVisualizationWidget::render(GUI::PaintEvent& event, FixedArray<double> const& samples)
|
||||
void BarsVisualizationWidget::render(GUI::PaintEvent& event, FixedArray<float> const& samples)
|
||||
{
|
||||
GUI::Frame::paint_event(event);
|
||||
GUI::Painter painter(*this);
|
||||
|
@ -30,44 +30,44 @@ void BarsVisualizationWidget::render(GUI::PaintEvent& event, FixedArray<double>
|
|||
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());
|
||||
AK::TypedTransfer<float>::copy(m_previous_samples.data(), samples.data(), samples.size());
|
||||
|
||||
LibDSP::fft(m_fft_samples.span(), false);
|
||||
|
||||
Array<double, bar_count> groups {};
|
||||
Array<float, bar_count> groups {};
|
||||
|
||||
if (m_logarithmic_spectrum) {
|
||||
auto const log_bar_size = static_cast<double>(bar_count) / AK::log2(fft_size);
|
||||
auto const log_bar_size = static_cast<float>(bar_count) / AK::log2(fft_size);
|
||||
|
||||
for (size_t i = 0; i < bar_count; ++i) {
|
||||
auto const bar_start = i == 0 ? 0 : static_cast<size_t>(floor(AK::pow(2., static_cast<double>(i) / log_bar_size)));
|
||||
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 bar_start = i == 0 ? 0 : static_cast<size_t>(floor(AK::pow(2.f, static_cast<float>(i) / log_bar_size)));
|
||||
auto const bar_end = clamp(static_cast<size_t>(floor(AK::pow(2.f, static_cast<float>(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();
|
||||
float const magnitude = m_fft_samples[sample_index].magnitude();
|
||||
groups[i] += magnitude;
|
||||
}
|
||||
groups[i] /= static_cast<double>(values_in_bar);
|
||||
groups[i] /= static_cast<float>(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();
|
||||
float 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();
|
||||
float const magnitude = m_fft_samples[i + j].magnitude();
|
||||
groups[i / values_per_bar] += magnitude;
|
||||
}
|
||||
groups[i / values_per_bar] /= values_per_bar;
|
||||
}
|
||||
}
|
||||
|
||||
double const max_peak_value = AK::sqrt(static_cast<double>(fft_size * 2));
|
||||
float const max_peak_value = AK::sqrt(static_cast<float>(fft_size * 2));
|
||||
for (size_t i = 0; i < bar_count; i++) {
|
||||
groups[i] = AK::log(groups[i] + 1) / AK::log(max_peak_value);
|
||||
if (m_adjust_frequencies)
|
||||
groups[i] *= 1 + 2.0 * (static_cast<double>(i) - static_cast<double>(bar_count / 3)) / static_cast<double>(bar_count);
|
||||
groups[i] *= 1 + 2.0f * (static_cast<float>(i) - bar_count / 3.0f) / static_cast<float>(bar_count);
|
||||
}
|
||||
|
||||
int const horizontal_margin = 30;
|
||||
|
@ -77,8 +77,8 @@ void BarsVisualizationWidget::render(GUI::PaintEvent& event, FixedArray<double>
|
|||
int const max_height = frame_inner_rect().height() - top_vertical_margin;
|
||||
int current_xpos = horizontal_margin;
|
||||
for (size_t g = 0; g < bar_count; g++) {
|
||||
m_gfx_falling_bars[g] = AK::min(clamp(max_height - (int)(groups[g] * max_height * 0.8), 0, max_height), m_gfx_falling_bars[g]);
|
||||
painter.fill_rect(Gfx::Rect(current_xpos, max_height - (int)(groups[g] * max_height * 0.8), pixel_per_group_width, (int)(groups[g] * max_height * 0.8)), Gfx::Color::from_rgb(0x95d437));
|
||||
m_gfx_falling_bars[g] = AK::min(clamp(max_height - static_cast<int>(groups[g] * static_cast<float>(max_height) * 0.8f), 0, max_height), m_gfx_falling_bars[g]);
|
||||
painter.fill_rect(Gfx::Rect(current_xpos, max_height - static_cast<int>(groups[g] * static_cast<float>(max_height) * 0.8f), pixel_per_group_width, static_cast<int>(groups[g] * max_height * 0.8f)), Gfx::Color::from_rgb(0x95d437));
|
||||
painter.fill_rect(Gfx::Rect(current_xpos, m_gfx_falling_bars[g], pixel_per_group_width, 2), Gfx::Color::White);
|
||||
current_xpos += pixel_per_group_width + pixels_inbetween_groups;
|
||||
m_gfx_falling_bars[g] += 3;
|
||||
|
@ -102,7 +102,7 @@ BarsVisualizationWidget::BarsVisualizationWidget()
|
|||
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<float>::hann<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));
|
||||
|
|
|
@ -22,7 +22,7 @@ public:
|
|||
private:
|
||||
BarsVisualizationWidget();
|
||||
|
||||
void render(GUI::PaintEvent&, FixedArray<double> const&) override;
|
||||
void render(GUI::PaintEvent&, FixedArray<float> const&) override;
|
||||
void context_menu_event(GUI::ContextMenuEvent& event) override;
|
||||
|
||||
static constexpr size_t fft_size = 512;
|
||||
|
@ -30,9 +30,9 @@ private:
|
|||
// 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<double, fft_size> m_fft_window {};
|
||||
Array<double, fft_size / 2> m_previous_samples {};
|
||||
Array<Complex<float>, fft_size> m_fft_samples {};
|
||||
Array<float, fft_size> m_fft_window {};
|
||||
Array<float, fft_size / 2> m_previous_samples {};
|
||||
Array<int, bar_count> m_gfx_falling_bars {};
|
||||
bool m_is_using_last;
|
||||
bool m_adjust_frequencies;
|
||||
|
|
|
@ -14,7 +14,7 @@ SampleWidget::SampleWidget()
|
|||
MUST(set_render_sample_count(512));
|
||||
}
|
||||
|
||||
void SampleWidget::render(GUI::PaintEvent& event, FixedArray<double> const& samples)
|
||||
void SampleWidget::render(GUI::PaintEvent& event, FixedArray<float> const& samples)
|
||||
{
|
||||
GUI::Frame::paint_event(event);
|
||||
GUI::Painter painter(*this);
|
||||
|
|
|
@ -17,5 +17,5 @@ public:
|
|||
|
||||
private:
|
||||
SampleWidget();
|
||||
virtual void render(GUI::PaintEvent&, FixedArray<double> const& samples) override;
|
||||
virtual void render(GUI::PaintEvent&, FixedArray<float> const& samples) override;
|
||||
};
|
||||
|
|
|
@ -17,7 +17,7 @@ class VisualizationWidget : public GUI::Frame {
|
|||
C_OBJECT_ABSTRACT(VisualizationWidget)
|
||||
|
||||
public:
|
||||
virtual void render(GUI::PaintEvent&, FixedArray<double> const& samples) = 0;
|
||||
virtual void render(GUI::PaintEvent&, FixedArray<float> const& samples) = 0;
|
||||
|
||||
void set_buffer(FixedArray<Audio::Sample> const& buffer)
|
||||
{
|
||||
|
@ -28,7 +28,7 @@ public:
|
|||
m_sample_buffer.resize(buffer.size());
|
||||
|
||||
for (size_t i = 0; i < buffer.size(); i++)
|
||||
m_sample_buffer.data()[i] = (buffer[i].left + buffer[i].right) / 2.;
|
||||
m_sample_buffer.data()[i] = (buffer[i].left + buffer[i].right) / 2.f;
|
||||
|
||||
m_frame_count = 0;
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ public:
|
|||
if (buffer_position + m_render_buffer.size() >= m_sample_buffer.size())
|
||||
buffer_position = m_sample_buffer.size() - m_render_buffer.size();
|
||||
|
||||
AK::TypedTransfer<double>::copy(m_render_buffer.data(), m_sample_buffer.span().slice(buffer_position).data(), m_render_buffer.size());
|
||||
AK::TypedTransfer<float>::copy(m_render_buffer.data(), m_sample_buffer.span().slice(buffer_position).data(), m_render_buffer.size());
|
||||
|
||||
render(event, m_render_buffer);
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ public:
|
|||
|
||||
ErrorOr<void> set_render_sample_count(size_t count)
|
||||
{
|
||||
auto new_buffer = TRY(FixedArray<double>::try_create(count));
|
||||
auto new_buffer = TRY(FixedArray<float>::try_create(count));
|
||||
m_render_buffer.swap(new_buffer);
|
||||
return {};
|
||||
}
|
||||
|
@ -79,8 +79,8 @@ public:
|
|||
protected:
|
||||
int m_samplerate;
|
||||
size_t m_frame_count;
|
||||
Vector<double> m_sample_buffer;
|
||||
FixedArray<double> m_render_buffer;
|
||||
Vector<float> m_sample_buffer;
|
||||
FixedArray<float> m_render_buffer;
|
||||
|
||||
static constexpr size_t REFRESH_TIME_MILLISECONDS = 30;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue