diff --git a/Utilities/bin_patch.cpp b/Utilities/bin_patch.cpp index 8d3fa1dee2..71106f30e1 100644 --- a/Utilities/bin_patch.cpp +++ b/Utilities/bin_patch.cpp @@ -1732,7 +1732,7 @@ void patch_engine::save_config(const patch_map& patches_map) fs::pending_file file(path); - if (!file.file || (file.file.write(out.c_str(), out.size()), !file.commit())) + if (!file.file || file.file.write(out.c_str(), out.size() < out.size() || !file.commit())) { patch_log.error("Failed to create patch config file %s (error=%s)", path, fs::g_tls_error); } diff --git a/rpcs3/Emu/Cell/Modules/cellMusic.cpp b/rpcs3/Emu/Cell/Modules/cellMusic.cpp index 157cf1906f..83937f7d16 100644 --- a/rpcs3/Emu/Cell/Modules/cellMusic.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMusic.cpp @@ -177,6 +177,11 @@ struct music_state return CELL_MUSIC_ERROR_NO_MORE_CONTENT; } + if (!fs::is_file(path)) + { + cellMusic.error("set_playback_command: File does not exist: '%s'", path); + } + switch (command) { case CELL_MUSIC_PB_CMD_FASTFORWARD: diff --git a/rpcs3/Emu/Cell/Modules/cellMusicSelectionContext.cpp b/rpcs3/Emu/Cell/Modules/cellMusicSelectionContext.cpp index 8de86380d8..e9360ebf6e 100644 --- a/rpcs3/Emu/Cell/Modules/cellMusicSelectionContext.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMusicSelectionContext.cpp @@ -77,7 +77,7 @@ std::string music_selection_context::get_yaml_path() const if (!fs::create_path(path)) { - cellMusicSelectionContext.fatal("Failed to create path: %s (%s)", path, fs::g_tls_error); + cellMusicSelectionContext.fatal("get_yaml_path: Failed to create path: %s (%s)", path, fs::g_tls_error); } return path + hash + ".yml"; @@ -101,13 +101,18 @@ void music_selection_context::set_playlist(const std::string& path) continue; } - playlist.push_back(dir_path + std::string(path + "/" + dir_entry.name).substr(vfs_dir_path.length())); + std::string track = dir_path + std::string(path + "/" + dir_entry.name).substr(vfs_dir_path.length()); + cellMusicSelectionContext.notice("set_playlist: Adding track to playlist: '%s'. (path: '%s', name: '%s')", track, path, dir_entry.name); + playlist.push_back(std::move(track)); } } else { content_type = CELL_SEARCH_CONTENTTYPE_MUSIC; - playlist.push_back(dir_path + path.substr(vfs_dir_path.length())); + + std::string track = dir_path + path.substr(vfs_dir_path.length()); + cellMusicSelectionContext.notice("set_playlist: Adding track to playlist: '%s'. (path: '%s')", track, path); + playlist.push_back(std::move(track)); } valid = true; @@ -118,7 +123,7 @@ void music_selection_context::create_playlist(const std::string& new_hash) hash = new_hash; const std::string yaml_path = get_yaml_path(); - cellMusicSelectionContext.notice("Saving music playlist file %s", yaml_path); + cellMusicSelectionContext.notice("create_playlist: Saving music playlist file %s", yaml_path); YAML::Emitter out; out << YAML::BeginMap; @@ -140,9 +145,9 @@ void music_selection_context::create_playlist(const std::string& new_hash) fs::pending_file file(yaml_path); - if (!file.file || (file.file.write(out.c_str(), out.size()), !file.commit())) + if (!file.file || file.file.write(out.c_str(), out.size() < out.size() || !file.commit())) { - cellMusicSelectionContext.error("Failed to create music playlist file %s (error=%s)", yaml_path, fs::g_tls_error); + cellMusicSelectionContext.error("create_playlist: Failed to create music playlist file '%s' (error=%s)", yaml_path, fs::g_tls_error); } } @@ -151,7 +156,7 @@ bool music_selection_context::load_playlist() playlist.clear(); const std::string path = get_yaml_path(); - cellMusicSelectionContext.notice("Loading music playlist file %s", path); + cellMusicSelectionContext.notice("load_playlist: Loading music playlist file '%s'", path); std::string content; { @@ -160,7 +165,7 @@ bool music_selection_context::load_playlist() if (!file) { - cellMusicSelectionContext.error("Failed to load music playlist file %s: %s", path, fs::g_tls_error); + cellMusicSelectionContext.error("load_playlist: Failed to load music playlist file '%s': %s", path, fs::g_tls_error); return false; } @@ -171,7 +176,7 @@ bool music_selection_context::load_playlist() if (!error.empty() || !root) { - cellMusicSelectionContext.error("Failed to load music playlist file %s:\n%s", path, error); + cellMusicSelectionContext.error("load_playlist: Failed to load music playlist file '%s':\n%s", path, error); return false; } @@ -180,54 +185,54 @@ bool music_selection_context::load_playlist() const std::string version = get_yaml_node_value(root["Version"], err); if (!err.empty()) { - cellMusicSelectionContext.error("No Version entry found. Error: '%s' (file: %s)", err, path); + cellMusicSelectionContext.error("load_playlist: No Version entry found. Error: '%s' (file: '%s')", err, path); return false; } if (version != target_version) { - cellMusicSelectionContext.error("Version '%s' does not match music playlist target '%s' (file: %s)", version, target_version, path); + cellMusicSelectionContext.error("load_playlist: Version '%s' does not match music playlist target '%s' (file: '%s')", version, target_version, path); return false; } const std::string file_type = get_yaml_node_value(root["FileType"], err); if (!err.empty()) { - cellMusicSelectionContext.error("No FileType entry found. Error: '%s' (file: %s)", err, path); + cellMusicSelectionContext.error("load_playlist: No FileType entry found. Error: '%s' (file: '%s')", err, path); return false; } if (file_type != target_file_type) { - cellMusicSelectionContext.error("FileType '%s' does not match music playlist target '%s' (file: %s)", file_type, target_file_type, path); + cellMusicSelectionContext.error("load_playlist: FileType '%s' does not match music playlist target '%s' (file: '%s')", file_type, target_file_type, path); return false; } content_type = static_cast(get_yaml_node_value(root["ContentType"], err)); if (!err.empty()) { - cellMusicSelectionContext.error("No ContentType entry found. Error: '%s' (file: %s)", err, path); + cellMusicSelectionContext.error("load_playlist: No ContentType entry found. Error: '%s' (file: '%s')", err, path); return false; } context_option = static_cast(get_yaml_node_value(root["ContextOption"], err)); if (!err.empty()) { - cellMusicSelectionContext.error("No ContextOption entry found. Error: '%s' (file: %s)", err, path); + cellMusicSelectionContext.error("load_playlist: No ContextOption entry found. Error: '%s' (file: '%s')", err, path); return false; } repeat_mode = static_cast(get_yaml_node_value(root["RepeatMode"], err)); if (!err.empty()) { - cellMusicSelectionContext.error("No RepeatMode entry found. Error: '%s' (file: %s)", err, path); + cellMusicSelectionContext.error("load_playlist: No RepeatMode entry found. Error: '%s' (file: '%s')", err, path); return false; } first_track = get_yaml_node_value(root["FirstTrack"], err); if (!err.empty()) { - cellMusicSelectionContext.error("No FirstTrack entry found. Error: '%s' (file: %s)", err, path); + cellMusicSelectionContext.error("load_playlist: No FirstTrack entry found. Error: '%s' (file: '%s')", err, path); return false; } @@ -235,15 +240,17 @@ bool music_selection_context::load_playlist() if (!track_node || track_node.Type() != YAML::NodeType::Sequence) { - cellMusicSelectionContext.error("No Tracks entry found or Tracks is not a Sequence. (file: %s)", path); + cellMusicSelectionContext.error("load_playlist: No Tracks entry found or Tracks is not a Sequence. (file: '%s')", path); return false; } for (usz i = 0; i < track_node.size(); i++) { + cellMusicSelectionContext.notice("load_playlist: Adding track to playlist: '%s'. (file: '%s')", track_node[i].Scalar(), path); playlist.push_back(track_node[i].Scalar()); } + cellMusicSelectionContext.notice("load_playlist: Loaded music playlist file '%s' (context: %s)", path, to_string()); valid = true; return true; } @@ -254,13 +261,13 @@ void music_selection_context::set_track(std::string_view track) if (playlist.empty()) { - cellMusicSelectionContext.error("No tracks to play... (requested path='%s')", track); + cellMusicSelectionContext.error("set_track: No tracks to play... (requested path='%s')", track); return; } for (usz i = 0; i < playlist.size(); i++) { - cellMusicSelectionContext.error("Comparing track '%s' vs '%s'", track, playlist[i]); + cellMusicSelectionContext.error("set_track: Comparing track '%s' vs '%s'", track, playlist[i]); if (track.ends_with(playlist[i])) { first_track = current_track = static_cast(i); @@ -268,14 +275,14 @@ void music_selection_context::set_track(std::string_view track) } } - cellMusicSelectionContext.error("Track '%s' not found...", track); + cellMusicSelectionContext.error("set_track: Track '%s' not found...", track); } u32 music_selection_context::step_track(bool next) { if (playlist.empty()) { - cellMusicSelectionContext.error("No tracks to play..."); + cellMusicSelectionContext.error("step_track: No tracks to play..."); current_track = umax; return umax; } @@ -290,7 +297,7 @@ u32 music_selection_context::step_track(bool next) if (++current_track >= playlist.size()) { // We are at the end of the playlist. - cellMusicSelectionContext.notice("No more tracks to play in playlist..."); + cellMusicSelectionContext.notice("step_track: No more tracks to play in playlist..."); current_track = umax; return umax; } @@ -301,7 +308,7 @@ u32 music_selection_context::step_track(bool next) if (current_track == 0) { // We are at the start of the playlist. - cellMusicSelectionContext.notice("No more tracks to play in playlist..."); + cellMusicSelectionContext.notice("step_track: No more tracks to play in playlist..."); current_track = umax; return umax; } @@ -339,13 +346,13 @@ u32 music_selection_context::step_track(bool next) case CELL_SEARCH_REPEATMODE_NOREPEAT1: { // We are done. We only wanted to decode a single track. - cellMusicSelectionContext.notice("No more tracks to play..."); + cellMusicSelectionContext.notice("step_track: No more tracks to play..."); current_track = umax; return umax; } default: { - fmt::throw_exception("Unknown repeat mode %d", static_cast(repeat_mode)); + fmt::throw_exception("step_track: Unknown repeat mode %d", static_cast(repeat_mode)); } } @@ -354,7 +361,7 @@ u32 music_selection_context::step_track(bool next) if (next ? current_track == 0 : current_track == (playlist.size() - 1)) { // We reached the first or last track again. Let's shuffle! - cellMusicSelectionContext.notice("Shuffling playlist..."); + cellMusicSelectionContext.notice("step_track: Shuffling playlist..."); auto engine = std::default_random_engine{}; std::shuffle(std::begin(playlist), std::end(playlist), engine); } diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index b8f0a02209..95bcae1b89 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -328,6 +328,9 @@ true + + true + true @@ -610,6 +613,9 @@ true + + true + true @@ -865,6 +871,7 @@ + @@ -930,6 +937,16 @@ $(QTDIR)\bin\moc.exe;%(FullPath) $(QTDIR)\bin\moc.exe;%(FullPath) + + Moc%27ing music_player_dialog.h... + .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" + Moc%27ing music_player_dialog.h... + .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing pad_settings_dialog.h... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp @@ -1067,6 +1084,7 @@ + @@ -1937,6 +1955,18 @@ "$(QTDIR)\bin\uic.exe" -o ".\QTGeneratedFiles\ui_%(Filename).h" "%(FullPath)" + + + $(QTDIR)\bin\uic.exe;%(AdditionalInputs) + Uic%27ing %(Identity)... + .\QTGeneratedFiles\ui_%(Filename).h;%(Outputs) + "$(QTDIR)\bin\uic.exe" -o ".\QTGeneratedFiles\ui_%(Filename).h" "%(FullPath)" + $(QTDIR)\bin\uic.exe;%(AdditionalInputs) + Uic%27ing %(Identity)... + .\QTGeneratedFiles\ui_%(Filename).h;%(Outputs) + "$(QTDIR)\bin\uic.exe" -o ".\QTGeneratedFiles\ui_%(Filename).h" "%(FullPath)" + + $(QTDIR)\bin\uic.exe;%(AdditionalInputs) diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 582e8ac59b..6394ef671d 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -273,6 +273,12 @@ Generated Files\Release + + Generated Files\Debug + + + Generated Files\Release + Generated Files\Debug @@ -435,6 +441,9 @@ Gui + + Gui\misc dialogs + Generated Files\Debug @@ -1202,6 +1211,9 @@ Generated Files + + Generated Files + Generated Files @@ -1423,6 +1435,9 @@ Form Files + + Form Files + Form Files @@ -1480,6 +1495,9 @@ Gui + + Gui\misc dialogs + Gui\dev tools diff --git a/rpcs3/rpcs3qt/CMakeLists.txt b/rpcs3/rpcs3qt/CMakeLists.txt index 1c8875c372..68fa4b9e76 100644 --- a/rpcs3/rpcs3qt/CMakeLists.txt +++ b/rpcs3/rpcs3qt/CMakeLists.txt @@ -57,6 +57,7 @@ add_library(rpcs3_ui STATIC movie_item.cpp movie_item_base.cpp msg_dialog_frame.cpp + music_player_dialog.cpp osk_dialog_frame.cpp pad_led_settings_dialog.cpp pad_motion_settings_dialog.cpp @@ -119,6 +120,7 @@ add_library(rpcs3_ui STATIC about_dialog.ui camera_settings_dialog.ui main_window.ui + music_player_dialog.ui pad_led_settings_dialog.ui pad_motion_settings_dialog.ui pad_settings_dialog.ui diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index c72d7f4c62..5fd5bac9c6 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -41,6 +41,7 @@ #include "basic_mouse_settings_dialog.h" #include "vfs_tool_dialog.h" #include "welcome_dialog.h" +#include "music_player_dialog.h" #include #include @@ -3143,6 +3144,12 @@ void main_window::CreateConnects() dlg->show(); }); + connect(ui->actionMusic_Player, &QAction::triggered, this, [this]() + { + music_player_dialog* dlg = new music_player_dialog(this); + dlg->open(); + }); + connect(ui->showDebuggerAct, &QAction::triggered, this, [this](bool checked) { checked ? m_debugger_frame->show() : m_debugger_frame->hide(); diff --git a/rpcs3/rpcs3qt/main_window.ui b/rpcs3/rpcs3qt/main_window.ui index 9cf59d35a0..845874d00b 100644 --- a/rpcs3/rpcs3qt/main_window.ui +++ b/rpcs3/rpcs3qt/main_window.ui @@ -318,6 +318,7 @@ + @@ -1424,6 +1425,11 @@ Prefer Game Data Icons + + + Music Player + + diff --git a/rpcs3/rpcs3qt/music_player_dialog.cpp b/rpcs3/rpcs3qt/music_player_dialog.cpp new file mode 100644 index 0000000000..89c262bb85 --- /dev/null +++ b/rpcs3/rpcs3qt/music_player_dialog.cpp @@ -0,0 +1,47 @@ +#include "music_player_dialog.h" +#include "ui_music_player_dialog.h" +#include "qt_music_handler.h" +#include "Emu/System.h" +#include "Emu/VFS.h" + +#include +#include + +music_player_dialog::music_player_dialog(QWidget* parent) + : QDialog(parent), ui(new Ui::music_player_dialog) +{ + setAttribute(Qt::WA_DeleteOnClose); + + ui->setupUi(this); + + m_handler = std::make_unique(); + + connect(ui->fileSelectButton, &QPushButton::clicked, this, [this](){ select_file(); }); + connect(ui->playButton, &QPushButton::clicked, this, [this](){ m_handler->play(m_file_path); }); + connect(ui->pauseButton, &QPushButton::clicked, this, [this](){ m_handler->pause(); }); + connect(ui->stopButton, &QPushButton::clicked, this, [this](){ m_handler->stop(); }); + connect(ui->forwardButton, &QPushButton::clicked, this, [this](){ m_handler->fast_forward(m_file_path); }); + connect(ui->reverseButton, &QPushButton::clicked, this, [this](){ m_handler->fast_reverse(m_file_path); }); + connect(ui->volumeSlider, &QSlider::valueChanged, this, [this](int value){ m_handler->set_volume(std::clamp(value / 100.0f, 0.0f, 1.0f)); }); +} + +music_player_dialog::~music_player_dialog() +{ +} + +void music_player_dialog::select_file() +{ + // Initialize Emu if not yet initialized (e.g. Emu.Kill() was previously invoked) before using some of the following vfs:: functions (e.g. vfs::get()) + if (Emu.IsStopped()) + { + Emu.Init(); + } + + const std::string vfs_dir_path = vfs::get("/dev_hdd0/music"); + const QString file_path = QFileDialog::getOpenFileName(this, tr("Select audio file"), QString::fromStdString(vfs_dir_path), tr("Audio files (*.mp3;*.wav;*.aac;*.ogg;*.flac;*.m4a;*.alac);;All files (*.*)")); + + if (!file_path.isEmpty()) + { + m_file_path = file_path.toStdString(); + } +} diff --git a/rpcs3/rpcs3qt/music_player_dialog.h b/rpcs3/rpcs3qt/music_player_dialog.h new file mode 100644 index 0000000000..a3fdc852ed --- /dev/null +++ b/rpcs3/rpcs3qt/music_player_dialog.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +class music_handler_base; + +namespace Ui +{ + class music_player_dialog; +} + +class music_player_dialog : public QDialog +{ + Q_OBJECT + +public: + explicit music_player_dialog(QWidget* parent = nullptr); + ~music_player_dialog(); + +private: + void select_file(); + + std::unique_ptr ui; + std::unique_ptr m_handler; + std::string m_file_path; +}; diff --git a/rpcs3/rpcs3qt/music_player_dialog.ui b/rpcs3/rpcs3qt/music_player_dialog.ui new file mode 100644 index 0000000000..27728cebee --- /dev/null +++ b/rpcs3/rpcs3qt/music_player_dialog.ui @@ -0,0 +1,167 @@ + + + music_player_dialog + + + + 0 + 0 + 400 + 300 + + + + Music Player + + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + Select file + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + + 6 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Qt::Orientation::Horizontal + + + QSizePolicy::Policy::MinimumExpanding + + + + 0 + 0 + + + + + + + + Vol: + + + + + + + 100 + + + 50 + + + Qt::Orientation::Horizontal + + + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/rpcs3/rpcs3qt/qt_music_handler.cpp b/rpcs3/rpcs3qt/qt_music_handler.cpp index 21ce264b84..e2a3b79df8 100644 --- a/rpcs3/rpcs3qt/qt_music_handler.cpp +++ b/rpcs3/rpcs3qt/qt_music_handler.cpp @@ -2,6 +2,7 @@ #include "Emu/Cell/Modules/cellMusic.h" #include "Emu/System.h" #include "util/logs.hpp" +#include "Utilities/File.h" #include #include @@ -68,11 +69,12 @@ qt_music_handler::qt_music_handler() music_log.notice("Constructing Qt music handler..."); m_media_player = std::make_unique(); - m_media_player->setAudioOutput(new QAudioOutput()); + m_media_player->setAudioOutput(new QAudioOutput(m_media_player.get())); connect(m_media_player.get(), &QMediaPlayer::mediaStatusChanged, this, &qt_music_handler::handle_media_status); connect(m_media_player.get(), &QMediaPlayer::playbackStateChanged, this, &qt_music_handler::handle_music_state); connect(m_media_player.get(), &QMediaPlayer::errorOccurred, this, &qt_music_handler::handle_music_error); + connect(m_media_player->audioOutput(), &QAudioOutput::volumeChanged, this, &qt_music_handler::handle_volume_change); } qt_music_handler::~qt_music_handler() @@ -117,13 +119,18 @@ void qt_music_handler::play(const std::string& path) Emu.BlockingCallFromMainThread([&path, this]() { + if (!fs::is_file(path)) + { + music_log.error("play: File does not exist: '%s'", path); + } + if (m_path != path) { m_path = path; m_media_player->setSource(QUrl::fromLocalFile(QString::fromStdString(path))); } - music_log.notice("Playing music: %s", path); + music_log.notice("Playing music: '%s'", path); m_media_player->setPlaybackRate(1.0); m_media_player->play(); }); @@ -137,13 +144,18 @@ void qt_music_handler::fast_forward(const std::string& path) Emu.BlockingCallFromMainThread([&path, this]() { + if (!fs::is_file(path)) + { + music_log.error("fast_forward: File does not exist: '%s'", path); + } + if (m_path != path) { m_path = path; m_media_player->setSource(QUrl::fromLocalFile(QString::fromStdString(path))); } - music_log.notice("Fast-forwarding music..."); + music_log.notice("Fast-forwarding music: '%s'", path); m_media_player->setPlaybackRate(2.0); m_media_player->play(); }); @@ -157,13 +169,18 @@ void qt_music_handler::fast_reverse(const std::string& path) Emu.BlockingCallFromMainThread([&path, this]() { + if (!fs::is_file(path)) + { + music_log.error("fast_reverse: File does not exist: '%s'", path); + } + if (m_path != path) { m_path = path; m_media_player->setSource(QUrl::fromLocalFile(QString::fromStdString(path))); } - music_log.notice("Fast-reversing music..."); + music_log.notice("Fast-reversing music: '%s'", path); m_media_player->setPlaybackRate(-2.0); // NOTE: This doesn't work on the current Qt version m_media_player->play(); }); @@ -234,3 +251,8 @@ void qt_music_handler::handle_music_error(QMediaPlayer::Error error, const QStri { music_log.error("Error event: \"%s\" (error=%s)", errorString, error); } + +void qt_music_handler::handle_volume_change(float volume) const +{ + music_log.notice("Volume changed: %f", volume); +} diff --git a/rpcs3/rpcs3qt/qt_music_handler.h b/rpcs3/rpcs3qt/qt_music_handler.h index 9e62e06ce2..559995a4cb 100644 --- a/rpcs3/rpcs3qt/qt_music_handler.h +++ b/rpcs3/rpcs3qt/qt_music_handler.h @@ -26,6 +26,7 @@ private Q_SLOTS: void handle_media_status(QMediaPlayer::MediaStatus status); void handle_music_state(QMediaPlayer::PlaybackState state); void handle_music_error(QMediaPlayer::Error error, const QString& errorString); + void handle_volume_change(float volume) const; private: mutable std::mutex m_mutex;