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)