From 885e35e92ca997fc1e64514e8a0b4ab54a6b1aec Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Mon, 6 Feb 2023 20:01:51 +0100 Subject: [PATCH] Piano: Use Sample struct from LibDSP Removes the Sample struct inside Piano and replaces it with the struct from LibDSP. It automatically scales the height of the wave depending on the maximum amplitude, as the Samples now contain floats and not integers. --- Userland/Applications/Piano/Music.h | 5 ----- Userland/Applications/Piano/WaveWidget.cpp | 22 ++++++++++++---------- Userland/Applications/Piano/WaveWidget.h | 6 +++++- Userland/Libraries/LibAudio/Sample.h | 13 +++++++++++++ 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/Userland/Applications/Piano/Music.h b/Userland/Applications/Piano/Music.h index 5d1d8235ce..70976149e3 100644 --- a/Userland/Applications/Piano/Music.h +++ b/Userland/Applications/Piano/Music.h @@ -19,11 +19,6 @@ namespace Music { // - 44,100 samples/sec // - 1,411.2 kbps -struct Sample { - i16 left; - i16 right; -}; - constexpr int sample_count = Audio::AUDIO_BUFFER_SIZE * 10; constexpr double sample_rate = 44100; diff --git a/Userland/Applications/Piano/WaveWidget.cpp b/Userland/Applications/Piano/WaveWidget.cpp index 1a9edf03d9..cdb6b1942c 100644 --- a/Userland/Applications/Piano/WaveWidget.cpp +++ b/Userland/Applications/Piano/WaveWidget.cpp @@ -9,6 +9,7 @@ #include "WaveWidget.h" #include "TrackManager.h" #include +#include #include WaveWidget::WaveWidget(TrackManager& track_manager) @@ -16,12 +17,12 @@ WaveWidget::WaveWidget(TrackManager& track_manager) { } -int WaveWidget::sample_to_y(int sample) const +int WaveWidget::sample_to_y(float sample, float sample_max) const { - // Sample scaling that looks good, experimentally determined. - constexpr double nice_scale_factor = 1.0; - constexpr double sample_max = NumericLimits::max(); - double percentage = sample / sample_max * nice_scale_factor; + if (sample_max < 1.0f) + sample_max = 1.0f; + sample_max *= rescale_factor; + double percentage = static_cast(sample) / static_cast(sample_max); double portion_of_half_height = percentage * ((frame_inner_rect().height() - 1) / 2.0); double y = (frame_inner_rect().height() / 2.0) + portion_of_half_height; return y; @@ -36,18 +37,19 @@ void WaveWidget::paint_event(GUI::PaintEvent& event) Color left_wave_color = left_wave_colors[m_track_manager.current_track()->synth()->wave()]; Color right_wave_color = right_wave_colors[m_track_manager.current_track()->synth()->wave()]; // FIXME: We can't get the last buffer from the track manager anymore - auto buffer = FixedArray::must_create_but_fixme_should_propagate_errors(sample_count); + auto buffer = FixedArray::must_create_but_fixme_should_propagate_errors(sample_count); double width_scale = static_cast(frame_inner_rect().width()) / buffer.size(); + auto const maximum = Audio::Sample::max_range(buffer.span()); int prev_x = 0; - int prev_y_left = sample_to_y(buffer[0].left); - int prev_y_right = sample_to_y(buffer[0].right); + int prev_y_left = sample_to_y(buffer[0].left, maximum.left); + int prev_y_right = sample_to_y(buffer[0].right, maximum.right); painter.set_pixel({ prev_x, prev_y_left }, left_wave_color); painter.set_pixel({ prev_x, prev_y_right }, right_wave_color); for (size_t x = 1; x < buffer.size(); ++x) { - int y_left = sample_to_y(buffer[x].left); - int y_right = sample_to_y(buffer[x].right); + int y_left = sample_to_y(buffer[x].left, maximum.left); + int y_right = sample_to_y(buffer[x].right, maximum.right); Gfx::IntPoint point1_left(prev_x * width_scale, prev_y_left); Gfx::IntPoint point2_left(x * width_scale, y_left); diff --git a/Userland/Applications/Piano/WaveWidget.h b/Userland/Applications/Piano/WaveWidget.h index 37f3433f63..3440f5be89 100644 --- a/Userland/Applications/Piano/WaveWidget.h +++ b/Userland/Applications/Piano/WaveWidget.h @@ -8,6 +8,7 @@ #pragma once +#include #include class TrackManager; @@ -18,11 +19,14 @@ public: virtual ~WaveWidget() override = default; private: + // Scales the sample-y value down by a bit, so that it doesn't look like it is clipping. + static constexpr float rescale_factor = 1.2f; + explicit WaveWidget(TrackManager&); virtual void paint_event(GUI::PaintEvent&) override; - int sample_to_y(int sample) const; + int sample_to_y(float sample, float sample_max) const; TrackManager& m_track_manager; }; diff --git a/Userland/Libraries/LibAudio/Sample.h b/Userland/Libraries/LibAudio/Sample.h index 2c55336dc6..33bd0ef241 100644 --- a/Userland/Libraries/LibAudio/Sample.h +++ b/Userland/Libraries/LibAudio/Sample.h @@ -38,6 +38,19 @@ struct Sample { { } + // Returns the absolute maximum range (separate per channel) of the given sample buffer. + // For example { 0.8, 0 } means that samples on the left channel occupy the range { -0.8, 0.8 }, + // while all samples on the right channel are 0. + static Sample max_range(ReadonlySpan span) + { + Sample result { NumericLimits::min_normal(), NumericLimits::min_normal() }; + for (Sample sample : span) { + result.left = max(result.left, AK::fabs(sample.left)); + result.right = max(result.right, AK::fabs(sample.right)); + } + return result; + } + void clip() { if (left > 1)