ladybird/Userland/Applications/SoundPlayer/SoundPlayerWidgetAdvancedView.h
Nick Miller 9a2c80c791 SoundPlayer: Handle any input file sample rate
This commit addresses two issues:
1. If you play a 96 KHz Wave file, the slider position is incorrect,
   because it is assumed all files are 44.1 KHz.
2. For high-bitrate files, there are audio dropouts due to not
   buffering enough audio data.

Issue 1 is addressed by scaling the number of played samples by the
ratio between the source and destination sample rates.

Issue 2 is addressed by buffering a certain number of milliseconds
worth of audio data (instead of a fixed number of bytes).
This makes the the buffer size independent of the source sample rate.

Some of the code is redesigned to be simpler. The code that did the
book-keeping of which buffers need to be loaded and which have been
already played has been removed. Instead, we enqueue a new buffer based
on a low watermark of samples remaining in the audio server queue.

Other small fixes include:
1. Disable the stop button when playback is finished.
2. Remove hard-coded instances of 44100.
3. Update the GUI every 50 ms (was 100), which improves visualizations.
2021-06-21 03:13:59 +04:30

67 lines
2 KiB
C++

/*
* Copyright (c) 2021, Cesar Torres <shortanemoia@protonmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include "BarsVisualizationWidget.h"
#include "Common.h"
#include "PlaybackManager.h"
#include "Player.h"
#include <AK/NonnullRefPtr.h>
#include <LibAudio/ClientConnection.h>
#include <LibGUI/Splitter.h>
#include <LibGUI/Widget.h>
class SoundPlayerWidgetAdvancedView final : public GUI::Widget
, public Player {
C_OBJECT(SoundPlayerWidgetAdvancedView)
public:
explicit SoundPlayerWidgetAdvancedView(GUI::Window& window, PlayerState& state);
~SoundPlayerWidgetAdvancedView() override;
void open_file(StringView path) override;
void read_playlist(StringView path);
void play() override;
void set_nonlinear_volume_slider(bool nonlinear);
void set_playlist_visible(bool visible);
void try_fill_missing_info(Vector<M3UEntry>& entries, StringView playlist_p);
template<typename T>
void set_visualization()
{
m_visualization->remove_from_parent();
update();
auto new_visualization = T::construct();
m_player_view->insert_child_before(new_visualization, *static_cast<Core::Object*>(m_playback_progress_slider.ptr()));
m_visualization = new_visualization;
}
private:
void drop_event(GUI::DropEvent& event) override;
GUI::Window& m_window;
RefPtr<GUI::HorizontalSplitter> m_splitter;
RefPtr<GUI::Widget> m_player_view;
RefPtr<PlaylistWidget> m_playlist_widget;
RefPtr<GUI::Widget> m_visualization;
RefPtr<Gfx::Bitmap> m_play_icon;
RefPtr<Gfx::Bitmap> m_pause_icon;
RefPtr<Gfx::Bitmap> m_stop_icon;
RefPtr<Gfx::Bitmap> m_back_icon;
RefPtr<Gfx::Bitmap> m_next_icon;
RefPtr<GUI::Button> m_play_button;
RefPtr<GUI::Button> m_stop_button;
RefPtr<GUI::Button> m_back_button;
RefPtr<GUI::Button> m_next_button;
RefPtr<AutoSlider> m_playback_progress_slider;
RefPtr<GUI::Label> m_volume_label;
bool m_nonlinear_volume_slider;
size_t m_device_sample_rate { 44100 };
};