diff options
author | Cesar Torres <shortanemoia@protonmail.com> | 2021-03-24 00:12:50 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-03-27 10:20:55 +0100 |
commit | e4d6a56a28d61d820c36efea0a553072b72ead4d (patch) | |
tree | c51a252bb2f0985b836b0ff69caa51833ddacfc3 /Userland/Applications/SoundPlayer | |
parent | f9e4bff487ed8f9571bd9a598d2f4b7c84f50897 (diff) | |
download | serenity-e4d6a56a28d61d820c36efea0a553072b72ead4d.zip |
AudioPlayer: Further decouple the player from the GUI
Diffstat (limited to 'Userland/Applications/SoundPlayer')
6 files changed, 136 insertions, 76 deletions
diff --git a/Userland/Applications/SoundPlayer/Player.h b/Userland/Applications/SoundPlayer/Player.h index b06e9b917b..598c8b0ca4 100644 --- a/Userland/Applications/SoundPlayer/Player.h +++ b/Userland/Applications/SoundPlayer/Player.h @@ -28,11 +28,48 @@ #include "PlaybackManager.h" #include "VisualizationBase.h" +#include <AK/RefPtr.h> + +struct PlayerState { + bool is_paused; + bool is_stopped; + bool has_loaded_file; + bool is_looping; + double volume; + Audio::ClientConnection& connection; + PlaybackManager& manager; + StringView loaded_filename; +}; class Player { public: - explicit Player() = default; + explicit Player(PlayerState& state) + : m_player_state(state) {}; virtual void open_file(StringView path) = 0; - virtual Audio::ClientConnection& client_connection() = 0; - virtual PlaybackManager& playback_manager() = 0; + virtual void play() = 0; + + PlayerState& get_player_state() { return m_player_state; } + bool is_stopped() const { return m_player_state.is_stopped; } + bool is_paused() const { return m_player_state.is_paused; } + bool has_loaded_file() const { return m_player_state.has_loaded_file; } + double volume() const { return m_player_state.volume; } + bool looping() const { return m_player_state.is_looping; } + StringView& loaded_filename() { return m_player_state.loaded_filename; } + + virtual void set_stopped(bool stopped) { m_player_state.is_stopped = stopped; } + virtual void set_paused(bool paused) { m_player_state.is_paused = paused; } + virtual void set_has_loaded_file(bool loaded) { m_player_state.has_loaded_file = loaded; } + virtual void set_volume(double volume) { m_player_state.volume = volume; } + virtual void set_looping(bool loop) + { + m_player_state.is_looping = loop; + manager().loop(loop); + } + virtual void set_loaded_filename(StringView& filename) { m_player_state.loaded_filename = filename; } + + Audio::ClientConnection& client_connection() { return m_player_state.connection; } + PlaybackManager& manager() { return m_player_state.manager; } + +protected: + PlayerState m_player_state; }; diff --git a/Userland/Applications/SoundPlayer/SoundPlayerWidget.cpp b/Userland/Applications/SoundPlayer/SoundPlayerWidget.cpp index 59c1932952..a37c02d388 100644 --- a/Userland/Applications/SoundPlayer/SoundPlayerWidget.cpp +++ b/Userland/Applications/SoundPlayer/SoundPlayerWidget.cpp @@ -33,10 +33,9 @@ #include <LibGUI/Label.h> #include <LibGUI/MessageBox.h> -SoundPlayerWidget::SoundPlayerWidget(GUI::Window& window, Audio::ClientConnection& connection, PlaybackManager& manager) - : m_window(window) - , m_connection(connection) - , m_manager(manager) +SoundPlayerWidget::SoundPlayerWidget(GUI::Window& window, PlayerState& state) + : Player(state) + , m_window(window) { window.set_resizable(false); window.resize(350, 140); @@ -68,8 +67,8 @@ SoundPlayerWidget::SoundPlayerWidget(GUI::Window& window, Audio::ClientConnectio m_slider = add<Slider>(Orientation::Horizontal); m_slider->set_min(0); - m_slider->set_enabled(false); - m_slider->on_knob_released = [&](int value) { m_manager.seek(denormalize_rate(value)); }; + m_slider->set_enabled(has_loaded_file()); + m_slider->on_knob_released = [&](int value) { manager().seek(denormalize_rate(value)); }; auto& control_widget = add<GUI::Widget>(); control_widget.set_fill_with_background_color(true); @@ -79,16 +78,21 @@ SoundPlayerWidget::SoundPlayerWidget(GUI::Window& window, Audio::ClientConnectio control_widget.layout()->set_spacing(10); m_play = control_widget.add<GUI::Button>(); - m_play->set_icon(*m_pause_icon); - m_play->set_enabled(false); + m_play->set_icon(has_loaded_file() ? *m_play_icon : *m_pause_icon); + m_play->set_enabled(has_loaded_file()); m_play->on_click = [this](auto) { - m_play->set_icon(m_manager.toggle_pause() ? *m_play_icon : *m_pause_icon); + bool paused = manager().toggle_pause(); + set_paused(paused); + m_play->set_icon(paused ? *m_play_icon : *m_pause_icon); }; m_stop = control_widget.add<GUI::Button>(); - m_stop->set_enabled(false); + m_stop->set_enabled(has_loaded_file()); m_stop->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/stop.png")); - m_stop->on_click = [this](auto) { m_manager.stop(); }; + m_stop->on_click = [this](auto) { + manager().stop(); + set_stopped(true); + }; m_status = add<GUI::Label>(); m_status->set_frame_shape(Gfx::FrameShape::Box); @@ -96,11 +100,11 @@ SoundPlayerWidget::SoundPlayerWidget(GUI::Window& window, Audio::ClientConnectio m_status->set_frame_thickness(4); m_status->set_text_alignment(Gfx::TextAlignment::CenterLeft); m_status->set_fixed_height(18); - m_status->set_text("No file open!"); + m_status->set_text(has_loaded_file() ? loaded_filename() : "No file open!"); update_position(0); - m_manager.on_update = [&]() { update_ui(); }; + manager().on_update = [&]() { update_ui(); }; } SoundPlayerWidget::~SoundPlayerWidget() @@ -132,8 +136,10 @@ void SoundPlayerWidget::open_file(StringView path) loader->num_channels(), loader->bits_per_sample())); - m_manager.set_loader(move(loader)); + manager().set_loader(move(loader)); update_position(0); + set_has_loaded_file(true); + set_loaded_filename(path); } void SoundPlayerWidget::drop_event(GUI::DropEvent& event) @@ -161,16 +167,16 @@ int SoundPlayerWidget::denormalize_rate(int rate) const void SoundPlayerWidget::update_ui() { - m_sample_widget->set_buffer(m_manager.current_buffer()); - m_play->set_icon(m_manager.is_paused() ? *m_play_icon : *m_pause_icon); - update_position(m_manager.connection()->get_played_samples()); + m_sample_widget->set_buffer(manager().current_buffer()); + m_play->set_icon(manager().is_paused() ? *m_play_icon : *m_pause_icon); + update_position(manager().connection()->get_played_samples()); } void SoundPlayerWidget::update_position(const int position) { - int total_norm_samples = position + normalize_rate(m_manager.last_seek()); + int total_norm_samples = position + normalize_rate(manager().last_seek()); float seconds = (total_norm_samples / static_cast<float>(PLAYBACK_MANAGER_RATE)); - float remaining_seconds = m_manager.total_length() - seconds; + float remaining_seconds = manager().total_length() - seconds; m_elapsed->set_text(String::formatted( "Elapsed:\n{}:{:02}.{:02}", @@ -191,3 +197,10 @@ void SoundPlayerWidget::hide_scope(bool hide) { m_sample_widget->set_visible(!hide); } + +void SoundPlayerWidget::play() +{ + manager().play(); + set_paused(false); + set_stopped(false); +} diff --git a/Userland/Applications/SoundPlayer/SoundPlayerWidget.h b/Userland/Applications/SoundPlayer/SoundPlayerWidget.h index 9f01a552ee..18f55176a8 100644 --- a/Userland/Applications/SoundPlayer/SoundPlayerWidget.h +++ b/Userland/Applications/SoundPlayer/SoundPlayerWidget.h @@ -40,16 +40,15 @@ class SoundPlayerWidget final : public GUI::Widget , public Player { C_OBJECT(SoundPlayerWidget) public: - virtual ~SoundPlayerWidget() override; + ~SoundPlayerWidget() override; void open_file(StringView path) override; + void play() override; void hide_scope(bool); - Audio::ClientConnection& client_connection() override { return m_connection; } - PlaybackManager& playback_manager() override { return m_manager; } private: - explicit SoundPlayerWidget(GUI::Window& window, Audio::ClientConnection& connection, PlaybackManager& manager); + explicit SoundPlayerWidget(GUI::Window& window, PlayerState& state); - virtual void drop_event(GUI::DropEvent&) override; + void drop_event(GUI::DropEvent&) override; void update_position(const int position); void update_ui(); @@ -57,8 +56,6 @@ private: int denormalize_rate(int) const; GUI::Window& m_window; - Audio::ClientConnection& m_connection; - PlaybackManager& m_manager; float m_sample_ratio { 1.0 }; RefPtr<GUI::Label> m_status; diff --git a/Userland/Applications/SoundPlayer/SoundPlayerWidgetAdvancedView.cpp b/Userland/Applications/SoundPlayer/SoundPlayerWidgetAdvancedView.cpp index c7eb311188..4d11fb4c0c 100644 --- a/Userland/Applications/SoundPlayer/SoundPlayerWidgetAdvancedView.cpp +++ b/Userland/Applications/SoundPlayer/SoundPlayerWidgetAdvancedView.cpp @@ -41,12 +41,10 @@ #include <LibGUI/Window.h> #include <LibGfx/Bitmap.h> -SoundPlayerWidgetAdvancedView::SoundPlayerWidgetAdvancedView(GUI::Window& window, Audio::ClientConnection& connection, PlaybackManager& manager) - : m_window(window) - , m_connection(connection) - , m_manager(manager) +SoundPlayerWidgetAdvancedView::SoundPlayerWidgetAdvancedView(GUI::Window& window, PlayerState& state) + : Player(state) + , m_window(window) { - window.resize(455, 350); window.set_minimum_size(440, 130); window.set_resizable(true); @@ -65,9 +63,9 @@ SoundPlayerWidgetAdvancedView::SoundPlayerWidgetAdvancedView(GUI::Window& window m_playback_progress_slider = add<Slider>(Orientation::Horizontal); m_playback_progress_slider->set_fixed_height(20); m_playback_progress_slider->set_min(0); - m_playback_progress_slider->set_max(m_manager.total_length() * 44100); //this value should be set when we load a new file + m_playback_progress_slider->set_max(this->manager().total_length() * 44100); //this value should be set when we load a new file m_playback_progress_slider->on_knob_released = [&](int value) { - m_manager.seek(value); + this->manager().seek(value); }; auto& toolbar_container = add<GUI::ToolBarContainer>(); @@ -75,20 +73,22 @@ SoundPlayerWidgetAdvancedView::SoundPlayerWidgetAdvancedView(GUI::Window& window auto& menubar = toolbar_container.add<GUI::ToolBar>(); m_play_button = menubar.add<GUI::Button>(); - m_play_button->set_icon(*m_play_icon); + m_play_button->set_icon(is_paused() ? (!has_loaded_file() ? *m_play_icon : *m_pause_icon) : *m_pause_icon); m_play_button->set_fixed_width(50); - + m_play_button->set_enabled(has_loaded_file()); m_play_button->on_click = [&](unsigned) { - bool paused = m_manager.toggle_pause(); + bool paused = this->manager().toggle_pause(); + set_paused(paused); m_play_button->set_icon(paused ? *m_play_icon : *m_pause_icon); - m_stop_button->set_enabled(!paused); }; m_stop_button = menubar.add<GUI::Button>(); m_stop_button->set_icon(*m_stop_icon); m_stop_button->set_fixed_width(50); + m_stop_button->set_enabled(has_loaded_file()); m_stop_button->on_click = [&](unsigned) { - m_manager.stop(); + this->manager().stop(); + set_stopped(true); m_play_button->set_icon(*m_play_icon); m_stop_button->set_enabled(false); }; @@ -100,13 +100,15 @@ SoundPlayerWidgetAdvancedView::SoundPlayerWidgetAdvancedView(GUI::Window& window // filler_label menubar.add<GUI::Label>(); - auto& back_button = menubar.add<GUI::Button>(); - back_button.set_fixed_width(50); - back_button.set_icon(*m_back_icon); + m_back_button = menubar.add<GUI::Button>(); + m_back_button->set_fixed_width(50); + m_back_button->set_icon(*m_back_icon); + m_back_button->set_enabled(has_loaded_file()); - auto& next_button = menubar.add<GUI::Button>(); - next_button.set_fixed_width(50); - next_button.set_icon(*m_next_icon); + m_next_button = menubar.add<GUI::Button>(); + m_next_button->set_fixed_width(50); + m_next_button->set_icon(*m_next_icon); + m_next_button->set_enabled(has_loaded_file()); m_volume_label = &menubar.add<GUI::Label>(); m_volume_label->set_fixed_width(30); @@ -127,41 +129,36 @@ SoundPlayerWidgetAdvancedView::SoundPlayerWidgetAdvancedView(GUI::Window& window set_volume(1.); set_nonlinear_volume_slider(false); - m_manager.on_update = [&]() { + manager().on_update = [&]() { //TODO: make this program support other sample rates - int samples_played = m_connection.get_played_samples() + m_manager.last_seek(); + int samples_played = client_connection().get_played_samples() + this->manager().last_seek(); int current_second = samples_played / 44100; timestamp_label.set_text(String::formatted("Elapsed: {:02}:{:02}:{:02}", current_second / 3600, current_second / 60, current_second % 60)); m_playback_progress_slider->set_value(samples_played); - dynamic_cast<Visualization*>(m_visualization.ptr())->set_buffer(m_manager.current_buffer()); + dynamic_cast<Visualization*>(m_visualization.ptr())->set_buffer(this->manager().current_buffer()); }; - m_manager.on_load_sample_buffer = [&](Audio::Buffer& buffer) { - if (m_volume == 1.) + this->manager().on_load_sample_buffer = [&](Audio::Buffer& buffer) { + if (volume() == 1.) return; auto sample_count = buffer.sample_count(); if (sample_count % 4 == 0) { const int total_iter = sample_count / (sizeof(AK::SIMD::f64x4) / sizeof(double) / 2); AK::SIMD::f64x4* sample_ptr = const_cast<AK::SIMD::f64x4*>(reinterpret_cast<const AK::SIMD::f64x4*>((buffer.data()))); for (int i = 0; i < total_iter; ++i) { - sample_ptr[i] = sample_ptr[i] * m_volume; + sample_ptr[i] = sample_ptr[i] * volume(); } } else { const int total_iter = sample_count / (sizeof(AK::SIMD::f64x2) / sizeof(double) / 2); AK::SIMD::f64x2* sample_ptr = const_cast<AK::SIMD::f64x2*>(reinterpret_cast<const AK::SIMD::f64x2*>((buffer.data()))); for (int i = 0; i < total_iter; ++i) { - sample_ptr[i] = sample_ptr[i] * m_volume; + sample_ptr[i] = sample_ptr[i] * volume(); } } }; } -void SoundPlayerWidgetAdvancedView::set_volume(double value) -{ - m_volume = value; -} - void SoundPlayerWidgetAdvancedView::open_file(StringView path) { NonnullRefPtr<Audio::Loader> loader = Audio::Loader::create(path); @@ -173,7 +170,12 @@ void SoundPlayerWidgetAdvancedView::open_file(StringView path) } m_window.set_title(String::formatted("{} - SoundPlayer", loader->file()->filename())); m_playback_progress_slider->set_max(loader->total_samples()); - m_manager.set_loader(move(loader)); + m_playback_progress_slider->set_enabled(true); + m_play_button->set_enabled(true); + m_stop_button->set_enabled(true); + manager().set_loader(move(loader)); + set_has_loaded_file(true); + set_loaded_filename(path); } void SoundPlayerWidgetAdvancedView::set_nonlinear_volume_slider(bool nonlinear) @@ -196,5 +198,13 @@ void SoundPlayerWidgetAdvancedView::drop_event(GUI::DropEvent& event) SoundPlayerWidgetAdvancedView::~SoundPlayerWidgetAdvancedView() { - m_manager.on_load_sample_buffer = nullptr; + manager().on_load_sample_buffer = nullptr; + manager().on_update = nullptr; +} + +void SoundPlayerWidgetAdvancedView::play() +{ + manager().play(); + set_paused(false); + set_stopped(false); } diff --git a/Userland/Applications/SoundPlayer/SoundPlayerWidgetAdvancedView.h b/Userland/Applications/SoundPlayer/SoundPlayerWidgetAdvancedView.h index dfdf71a892..11755ad9cb 100644 --- a/Userland/Applications/SoundPlayer/SoundPlayerWidgetAdvancedView.h +++ b/Userland/Applications/SoundPlayer/SoundPlayerWidgetAdvancedView.h @@ -39,12 +39,11 @@ class SoundPlayerWidgetAdvancedView final : public GUI::Widget C_OBJECT(SoundPlayerWidgetAdvancedView) public: - explicit SoundPlayerWidgetAdvancedView(GUI::Window& window, Audio::ClientConnection& connection, PlaybackManager& manager); + explicit SoundPlayerWidgetAdvancedView(GUI::Window& window, PlayerState& state); ~SoundPlayerWidgetAdvancedView() override; void open_file(StringView path) override; - Audio::ClientConnection& client_connection() override { return m_connection; } - PlaybackManager& playback_manager() override { return m_manager; } + void play() override; template<typename T> void set_visualization() @@ -58,14 +57,9 @@ public: void set_nonlinear_volume_slider(bool nonlinear); - void set_volume(double value); - private: void drop_event(GUI::DropEvent& event) override; - GUI::Window& m_window; - Audio::ClientConnection& m_connection; - PlaybackManager& m_manager; RefPtr<GUI::Widget> m_visualization; @@ -77,9 +71,10 @@ private: 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<Slider> m_playback_progress_slider; RefPtr<GUI::Label> m_volume_label; - double m_volume; bool m_nonlinear_volume_slider; }; diff --git a/Userland/Applications/SoundPlayer/main.cpp b/Userland/Applications/SoundPlayer/main.cpp index a41ec64bec..72d2b313b4 100644 --- a/Userland/Applications/SoundPlayer/main.cpp +++ b/Userland/Applications/SoundPlayer/main.cpp @@ -54,8 +54,15 @@ int main(int argc, char** argv) auto audio_client = Audio::ClientConnection::construct(); audio_client->handshake(); - PlaybackManager playback_manager(audio_client); + PlayerState initial_player_state { true, + true, + false, + false, + 1.0, + audio_client, + playback_manager, + "" }; if (pledge("stdio recvfd sendfd accept rpath thread", nullptr) < 0) { perror("pledge"); @@ -72,11 +79,11 @@ int main(int argc, char** argv) auto& app_menu = menubar->add_menu("File"); // start in simple view by default - Player* player = &window->set_main_widget<SoundPlayerWidget>(window, audio_client, playback_manager); + Player* player = &window->set_main_widget<SoundPlayerWidget>(window, initial_player_state); if (argc > 1) { String path = argv[1]; player->open_file(path); - player->playback_manager().play(); + player->play(); } app_menu.add_action(GUI::CommonActions::make_open_action([&](auto&) { @@ -89,12 +96,13 @@ int main(int argc, char** argv) RefPtr<GUI::Action> hide_scope; auto advanced_view_check = GUI::Action::create_checkable("Advanced view", { Mod_Ctrl, Key_A }, [&](auto& action) { + PlayerState state = player->get_player_state(); window->close(); if (action.is_checked()) { - player = &window->set_main_widget<SoundPlayerWidgetAdvancedView>(window, audio_client, playback_manager); + player = &window->set_main_widget<SoundPlayerWidgetAdvancedView>(window, state); hide_scope->set_checkable(false); } else { - player = &window->set_main_widget<SoundPlayerWidget>(window, audio_client, playback_manager); + player = &window->set_main_widget<SoundPlayerWidget>(window, state); hide_scope->set_checkable(true); } window->show(); @@ -123,7 +131,7 @@ int main(int argc, char** argv) auto& playback_menu = menubar->add_menu("Playback"); auto loop = GUI::Action::create_checkable("Loop", { Mod_Ctrl, Key_R }, [&](auto& action) { - player->playback_manager().loop(action.is_checked()); + player->set_looping(action.is_checked()); }); playback_menu.add_action(move(loop)); |