summaryrefslogtreecommitdiff
path: root/Userland/Applications
diff options
context:
space:
mode:
authorLucas CHOLLET <lucas.chollet@free.fr>2022-10-04 01:07:18 +0200
committerAndrew Kaster <andrewdkaster@gmail.com>2022-11-13 18:51:18 -0700
commit7649feb26f83f35f4ea3eb42849df8b7a389cc12 (patch)
treea8f7bd9eed49b268cc01a47feb730e9aff92cc81 /Userland/Applications
parent27539440df543d50098dbd6b30912ebd2a33165f (diff)
downloadserenity-7649feb26f83f35f4ea3eb42849df8b7a389cc12.zip
SoundPlayer: Load cover image from music files
When the visualization is set to "Album Cover", the player will now try to load the embedded image. On failure, it defaults to a "Cover" image file in the directory. In Player::play_file_path, file_name_changed now needs to be executed after that the loader have been set, to get the correct image.
Diffstat (limited to 'Userland/Applications')
-rw-r--r--Userland/Applications/SoundPlayer/AlbumCoverVisualizationWidget.cpp18
-rw-r--r--Userland/Applications/SoundPlayer/AlbumCoverVisualizationWidget.h4
-rw-r--r--Userland/Applications/SoundPlayer/CMakeLists.txt2
-rw-r--r--Userland/Applications/SoundPlayer/Player.cpp8
-rw-r--r--Userland/Applications/SoundPlayer/Player.h3
-rw-r--r--Userland/Applications/SoundPlayer/SoundPlayerWidgetAdvancedView.h6
-rw-r--r--Userland/Applications/SoundPlayer/main.cpp24
7 files changed, 55 insertions, 10 deletions
diff --git a/Userland/Applications/SoundPlayer/AlbumCoverVisualizationWidget.cpp b/Userland/Applications/SoundPlayer/AlbumCoverVisualizationWidget.cpp
index ceb468e6cd..152fa32b67 100644
--- a/Userland/Applications/SoundPlayer/AlbumCoverVisualizationWidget.cpp
+++ b/Userland/Applications/SoundPlayer/AlbumCoverVisualizationWidget.cpp
@@ -12,13 +12,19 @@
#include <LibGUI/Painter.h>
#include <LibGfx/Rect.h>
+AlbumCoverVisualizationWidget::AlbumCoverVisualizationWidget(Function<RefPtr<Gfx::Bitmap>()> get_file_cover_from_player)
+ : m_get_file_cover_from_player(move(get_file_cover_from_player))
+{
+}
+
void AlbumCoverVisualizationWidget::paint_event(GUI::PaintEvent& event)
{
Frame::paint_event(event);
GUI::Painter painter(*this);
- if (m_album_cover) {
- auto album_cover_rect = m_album_cover->rect();
+ auto const& cover = m_file_cover ? m_file_cover : m_album_cover;
+ if (cover) {
+ auto album_cover_rect = cover->rect();
auto height_ratio = frame_inner_rect().height() / (float)album_cover_rect.height();
auto width_ratio = frame_inner_rect().width() / (float)album_cover_rect.width();
@@ -27,7 +33,7 @@ void AlbumCoverVisualizationWidget::paint_event(GUI::PaintEvent& event)
Gfx::IntRect fitted_rect = { 0, 0, (int)(album_cover_rect.width() * scale), (int)(album_cover_rect.height() * scale) };
fitted_rect.center_within(frame_inner_rect());
- painter.draw_scaled_bitmap(fitted_rect, *m_album_cover, m_album_cover->rect(), 1.0f);
+ painter.draw_scaled_bitmap(fitted_rect, *cover, cover->rect(), 1.0f);
} else {
if (!m_serenity_bg)
m_serenity_bg = Gfx::Bitmap::try_load_from_file("/res/wallpapers/sunset-retro.png"sv).release_value_but_fixme_should_propagate_errors();
@@ -51,6 +57,12 @@ ErrorOr<NonnullRefPtr<Gfx::Bitmap>> AlbumCoverVisualizationWidget::get_album_cov
void AlbumCoverVisualizationWidget::start_new_file(StringView filename)
{
+ if (m_get_file_cover_from_player)
+ m_file_cover = m_get_file_cover_from_player();
+
+ if (m_file_cover)
+ return;
+
auto album_cover_or_error = get_album_cover(filename);
if (album_cover_or_error.is_error())
m_album_cover = nullptr;
diff --git a/Userland/Applications/SoundPlayer/AlbumCoverVisualizationWidget.h b/Userland/Applications/SoundPlayer/AlbumCoverVisualizationWidget.h
index 48aeb357ba..fb30e1499f 100644
--- a/Userland/Applications/SoundPlayer/AlbumCoverVisualizationWidget.h
+++ b/Userland/Applications/SoundPlayer/AlbumCoverVisualizationWidget.h
@@ -14,6 +14,7 @@ class AlbumCoverVisualizationWidget final : public VisualizationWidget {
C_OBJECT(AlbumCoverVisualizationWidget)
public:
+ AlbumCoverVisualizationWidget(Function<RefPtr<Gfx::Bitmap>()> get_file_cover_from_player);
~AlbumCoverVisualizationWidget() override = default;
void start_new_file(StringView) override;
@@ -23,6 +24,9 @@ private:
AlbumCoverVisualizationWidget() = default;
ErrorOr<NonnullRefPtr<Gfx::Bitmap>> get_album_cover(StringView const filename);
+ Function<RefPtr<Gfx::Bitmap>()> m_get_file_cover_from_player;
+
RefPtr<Gfx::Bitmap> m_serenity_bg;
RefPtr<Gfx::Bitmap> m_album_cover;
+ RefPtr<Gfx::Bitmap> m_file_cover;
};
diff --git a/Userland/Applications/SoundPlayer/CMakeLists.txt b/Userland/Applications/SoundPlayer/CMakeLists.txt
index 325b95b7f9..173a34b5e2 100644
--- a/Userland/Applications/SoundPlayer/CMakeLists.txt
+++ b/Userland/Applications/SoundPlayer/CMakeLists.txt
@@ -19,4 +19,4 @@ set(SOURCES
)
serenity_app(SoundPlayer ICON app-sound-player)
-target_link_libraries(SoundPlayer PRIVATE LibAudio LibCore LibDSP LibGfx LibGUI LibIPC LibMain LibThreading)
+target_link_libraries(SoundPlayer PRIVATE LibAudio LibCore LibDSP LibGfx LibGUI LibIPC LibMain LibThreading LibImageDecoderClient)
diff --git a/Userland/Applications/SoundPlayer/Player.cpp b/Userland/Applications/SoundPlayer/Player.cpp
index 75bb45b876..47f1cbb0fd 100644
--- a/Userland/Applications/SoundPlayer/Player.cpp
+++ b/Userland/Applications/SoundPlayer/Player.cpp
@@ -6,6 +6,7 @@
*/
#include "Player.h"
+#include <LibAudio/FlacLoader.h>
#include <LibCore/File.h>
Player::Player(Audio::ConnectionToServer& audio_client_connection)
@@ -63,9 +64,9 @@ void Player::play_file_path(String const& path)
m_loaded_filename = path;
- file_name_changed(path);
total_samples_changed(loader->total_samples());
m_playback_manager.set_loader(move(loader));
+ file_name_changed(path);
play();
}
@@ -156,3 +157,8 @@ void Player::seek(int sample)
{
m_playback_manager.seek(sample);
}
+
+Vector<Audio::PictureData> const& Player::pictures() const
+{
+ return m_playback_manager.loader()->pictures();
+}
diff --git a/Userland/Applications/SoundPlayer/Player.h b/Userland/Applications/SoundPlayer/Player.h
index cd8872c590..ec2ef78660 100644
--- a/Userland/Applications/SoundPlayer/Player.h
+++ b/Userland/Applications/SoundPlayer/Player.h
@@ -11,6 +11,7 @@
#include "Playlist.h"
#include "PlaylistWidget.h"
#include <AK/RefPtr.h>
+#include <LibAudio/GenericTypes.h>
#include <LibAudio/Sample.h>
class Player {
@@ -75,6 +76,8 @@ public:
virtual void total_samples_changed(int) = 0;
virtual void sound_buffer_played(FixedArray<Audio::Sample> const&, [[maybe_unused]] int sample_rate, [[maybe_unused]] int samples_played) = 0;
+ Vector<Audio::PictureData> const& pictures() const;
+
protected:
void done_initializing()
{
diff --git a/Userland/Applications/SoundPlayer/SoundPlayerWidgetAdvancedView.h b/Userland/Applications/SoundPlayer/SoundPlayerWidgetAdvancedView.h
index 9c79ee720f..e17fb0f4ed 100644
--- a/Userland/Applications/SoundPlayer/SoundPlayerWidgetAdvancedView.h
+++ b/Userland/Applications/SoundPlayer/SoundPlayerWidgetAdvancedView.h
@@ -25,12 +25,12 @@ public:
void set_nonlinear_volume_slider(bool nonlinear);
void set_playlist_visible(bool visible);
- template<typename T>
- void set_visualization()
+ template<typename T, typename... Args>
+ void set_visualization(Args... args)
{
m_visualization->remove_from_parent();
update();
- auto new_visualization = T::construct();
+ auto new_visualization = T::construct(move(args)...);
m_player_view->insert_child_before(new_visualization, *static_cast<Core::Object*>(m_playback_progress_slider.ptr()));
m_visualization = new_visualization;
if (!loaded_filename().is_empty())
diff --git a/Userland/Applications/SoundPlayer/main.cpp b/Userland/Applications/SoundPlayer/main.cpp
index fc91cac584..f390439817 100644
--- a/Userland/Applications/SoundPlayer/main.cpp
+++ b/Userland/Applications/SoundPlayer/main.cpp
@@ -5,12 +5,16 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
+// FIXME: LibIPC Decoder and Encoder are sensitive to include order here
+#include <LibImageDecoderClient/Client.h>
+
#include "AlbumCoverVisualizationWidget.h"
#include "BarsVisualizationWidget.h"
#include "Player.h"
#include "SampleWidget.h"
#include "SoundPlayerWidgetAdvancedView.h"
#include <LibAudio/ConnectionToServer.h>
+#include <LibAudio/FlacLoader.h>
#include <LibCore/System.h>
#include <LibGUI/Action.h>
#include <LibGUI/ActionGroup.h>
@@ -21,7 +25,6 @@
#include <LibGUI/Window.h>
#include <LibGfx/CharacterBitmap.h>
#include <LibMain/Main.h>
-#include <stdio.h>
ErrorOr<int> serenity_main(Main::Arguments arguments)
{
@@ -29,6 +32,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
auto app = TRY(GUI::Application::try_create(arguments));
auto audio_client = TRY(Audio::ConnectionToServer::try_create());
+ auto decoder_client = TRY(ImageDecoderClient::Client::try_create());
TRY(Core::System::pledge("stdio recvfd sendfd rpath thread"));
@@ -125,7 +129,23 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
visualization_actions.add_action(samples);
auto album_cover_visualization = GUI::Action::create_checkable("&Album Cover", [&](auto&) {
- static_cast<SoundPlayerWidgetAdvancedView*>(player)->set_visualization<AlbumCoverVisualizationWidget>();
+ auto get_image_from_music_file = [&player, &decoder_client]() -> RefPtr<Gfx::Bitmap> {
+ auto const& pictures = player->pictures();
+
+ if (pictures.is_empty())
+ return {};
+
+ // FIXME: We randomly select the first picture available for the track,
+ // We might want to hardcode or let the user set a preference.
+ auto decoded_image_or_error = decoder_client->decode_image(pictures[0].data);
+ if (!decoded_image_or_error.has_value())
+ return {};
+
+ auto const decoded_image = decoded_image_or_error.release_value();
+ return decoded_image.frames[0].bitmap;
+ };
+
+ static_cast<SoundPlayerWidgetAdvancedView*>(player)->set_visualization<AlbumCoverVisualizationWidget>(get_image_from_music_file);
});
TRY(visualization_menu->try_add_action(album_cover_visualization));
visualization_actions.add_action(album_cover_visualization);