mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2024-12-29 11:06:07 +00:00
Add playback of background/title music in game list (#1033)
* add playback of background/title music * clang_format * add windows multimedia build instructions * fix typo accidentally made to arm * address comments * loop music * feedback * fix CI * add newline * playBGM off by default --------- Co-authored-by: Charles <charles@superfocus.ai>
This commit is contained in:
parent
396007bba3
commit
cac244cc03
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
|
@ -113,6 +113,7 @@ jobs:
|
|||
target: desktop
|
||||
arch: win64_msvc2019_64
|
||||
archives: qtbase qttools
|
||||
modules: qtmultimedia
|
||||
|
||||
- name: Cache CMake Configuration
|
||||
uses: actions/cache@v4
|
||||
|
@ -237,6 +238,7 @@ jobs:
|
|||
target: desktop
|
||||
arch: clang_64
|
||||
archives: qtbase qttools
|
||||
modules: qtmultimedia
|
||||
|
||||
- name: Cache CMake Configuration
|
||||
uses: actions/cache@v4
|
||||
|
@ -341,7 +343,7 @@ jobs:
|
|||
submodules: recursive
|
||||
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libfuse2 clang build-essential qt6-base-dev qt6-tools-dev
|
||||
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libfuse2 clang build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev
|
||||
|
||||
- name: Cache CMake Configuration
|
||||
uses: actions/cache@v4
|
||||
|
|
|
@ -144,7 +144,7 @@ add_subdirectory(externals)
|
|||
include_directories(src)
|
||||
|
||||
if(ENABLE_QT_GUI)
|
||||
find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent LinguistTools Network)
|
||||
find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent LinguistTools Network Multimedia)
|
||||
qt_standard_project_setup()
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
@ -653,6 +653,8 @@ qt_add_resources(RESOURCE_FILES src/shadps4.qrc)
|
|||
set(QT_GUI src/qt_gui/about_dialog.cpp
|
||||
src/qt_gui/about_dialog.h
|
||||
src/qt_gui/about_dialog.ui
|
||||
src/qt_gui/background_music_player.cpp
|
||||
src/qt_gui/background_music_player.h
|
||||
src/qt_gui/cheats_patches.cpp
|
||||
src/qt_gui/cheats_patches.h
|
||||
src/qt_gui/check_update.cpp
|
||||
|
@ -760,7 +762,7 @@ else()
|
|||
endif()
|
||||
|
||||
if (ENABLE_QT_GUI)
|
||||
target_link_libraries(shadps4 PRIVATE Qt6::Widgets Qt6::Concurrent Qt6::Network)
|
||||
target_link_libraries(shadps4 PRIVATE Qt6::Widgets Qt6::Concurrent Qt6::Network Qt6::Multimedia)
|
||||
add_definitions(-DENABLE_QT_GUI)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ Normal x86-based computers, follow:
|
|||
1. Open "MSYS2 MINGW64" from your new applications
|
||||
2. Run `pacman -Syu`, let it complete;
|
||||
3. Run `pacman -S --needed git mingw-w64-x86_64-binutils mingw-w64-x86_64-clang mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-ffmpeg`
|
||||
1. Optional (Qt only): run `pacman -S --needed mingw-w64-x86_64-qt6-base mingw-w64-x86_64-qt6-tools`
|
||||
1. Optional (Qt only): run `pacman -S --needed mingw-w64-x86_64-qt6-base mingw-w64-x86_64-qt6-tools mingw-w64-x86_64-qt6-multimedia`
|
||||
4. Run `git clone --depth 1 --recursive https://github.com/shadps4-emu/shadPS4`
|
||||
5. Run `cd shadPS4`
|
||||
6. Run `cmake -S . -B build -DCMAKE_C_COMPILER="clang.exe" -DCMAKE_CXX_COMPILER="clang++.exe" -DCMAKE_CXX_FLAGS="-O2 -march=native"`
|
||||
|
@ -94,7 +94,7 @@ ARM64-based computers, follow:
|
|||
1. Open "MSYS2 CLANGARM64" from your new applications
|
||||
2. Run `pacman -Syu`, let it complete;
|
||||
3. Run `pacman -S --needed git mingw-w64-clang-aarch64-binutils mingw-w64-clang-aarch64-clang mingw-w64-clang-aarch64-cmake mingw-w64-clang-aarch64-ninja mingw-w64-clang-aarch64-ffmpeg`
|
||||
1. Optional (Qt only): run `pacman -S --needed mingw-w64-clang-aarch64-qt6-base mingw-w64-clang-aarch64-qt6-tools`
|
||||
1. Optional (Qt only): run `pacman -S --needed mingw-w64-clang-aarch64-qt6-base mingw-w64-clang-aarch64-qt6-tools mingw-w64-clang-aarch64-qt6-multimedia`
|
||||
4. Run `git clone --depth 1 --recursive https://github.com/shadps4-emu/shadPS4`
|
||||
5. Run `cd shadPS4`
|
||||
6. Run `cmake -S . -B build -DCMAKE_C_COMPILER="clang.exe" -DCMAKE_CXX_COMPILER="clang++.exe" -DCMAKE_CXX_FLAGS="-O2 -march=native"`
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace Config {
|
|||
|
||||
static bool isNeo = false;
|
||||
static bool isFullscreen = false;
|
||||
static bool playBGM = false;
|
||||
static u32 screenWidth = 1280;
|
||||
static u32 screenHeight = 720;
|
||||
static s32 gpuId = -1; // Vulkan physical device index. Set to negative for auto select
|
||||
|
@ -64,6 +65,10 @@ bool isFullscreenMode() {
|
|||
return isFullscreen;
|
||||
}
|
||||
|
||||
bool getPlayBGM() {
|
||||
return playBGM;
|
||||
}
|
||||
|
||||
u32 getScreenWidth() {
|
||||
return screenWidth;
|
||||
}
|
||||
|
@ -220,6 +225,10 @@ void setFullscreenMode(bool enable) {
|
|||
isFullscreen = enable;
|
||||
}
|
||||
|
||||
void setPlayBGM(bool enable) {
|
||||
playBGM = enable;
|
||||
}
|
||||
|
||||
void setLanguage(u32 language) {
|
||||
m_language = language;
|
||||
}
|
||||
|
@ -379,6 +388,7 @@ void load(const std::filesystem::path& path) {
|
|||
|
||||
isNeo = toml::find_or<bool>(general, "isPS4Pro", false);
|
||||
isFullscreen = toml::find_or<bool>(general, "Fullscreen", false);
|
||||
playBGM = toml::find_or<bool>(general, "playBGM", false);
|
||||
logFilter = toml::find_or<std::string>(general, "logFilter", "");
|
||||
logType = toml::find_or<std::string>(general, "logType", "sync");
|
||||
userName = toml::find_or<std::string>(general, "userName", "shadPS4");
|
||||
|
@ -473,6 +483,7 @@ void save(const std::filesystem::path& path) {
|
|||
|
||||
data["General"]["isPS4Pro"] = isNeo;
|
||||
data["General"]["Fullscreen"] = isFullscreen;
|
||||
data["General"]["playBGM"] = playBGM;
|
||||
data["General"]["logFilter"] = logFilter;
|
||||
data["General"]["logType"] = logType;
|
||||
data["General"]["userName"] = userName;
|
||||
|
@ -524,6 +535,7 @@ void save(const std::filesystem::path& path) {
|
|||
void setDefaultValues() {
|
||||
isNeo = false;
|
||||
isFullscreen = false;
|
||||
playBGM = false;
|
||||
screenWidth = 1280;
|
||||
screenHeight = 720;
|
||||
logFilter = "";
|
||||
|
@ -550,4 +562,4 @@ void setDefaultValues() {
|
|||
gpuId = -1;
|
||||
}
|
||||
|
||||
} // namespace Config
|
||||
} // namespace Config
|
||||
|
|
|
@ -13,6 +13,7 @@ void save(const std::filesystem::path& path);
|
|||
|
||||
bool isNeoMode();
|
||||
bool isFullscreenMode();
|
||||
bool getPlayBGM();
|
||||
std::string getLogFilter();
|
||||
std::string getLogType();
|
||||
std::string getUserName();
|
||||
|
@ -47,6 +48,7 @@ void setGpuId(s32 selectedGpuId);
|
|||
void setScreenWidth(u32 width);
|
||||
void setScreenHeight(u32 height);
|
||||
void setFullscreenMode(bool enable);
|
||||
void setPlayBGM(bool enable);
|
||||
void setLanguage(u32 language);
|
||||
void setNeoMode(bool enable);
|
||||
void setUserName(const std::string& type);
|
||||
|
|
32
src/qt_gui/background_music_player.cpp
Normal file
32
src/qt_gui/background_music_player.cpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "background_music_player.h"
|
||||
|
||||
BackgroundMusicPlayer::BackgroundMusicPlayer(QObject* parent) : QObject(parent) {
|
||||
m_mediaPlayer = new QMediaPlayer(this);
|
||||
m_audioOutput = new QAudioOutput(this);
|
||||
m_mediaPlayer->setAudioOutput(m_audioOutput);
|
||||
m_mediaPlayer->setLoops(QMediaPlayer::Infinite);
|
||||
}
|
||||
|
||||
void BackgroundMusicPlayer::playMusic(const QString& snd0path) {
|
||||
if (snd0path.isEmpty()) {
|
||||
stopMusic();
|
||||
return;
|
||||
}
|
||||
const auto newMusic = QUrl::fromLocalFile(snd0path);
|
||||
if (m_mediaPlayer->playbackState() == QMediaPlayer::PlayingState &&
|
||||
m_currentMusic == newMusic) {
|
||||
// already playing the correct music
|
||||
return;
|
||||
}
|
||||
|
||||
m_currentMusic = newMusic;
|
||||
m_mediaPlayer->setSource(newMusic);
|
||||
m_mediaPlayer->play();
|
||||
}
|
||||
|
||||
void BackgroundMusicPlayer::stopMusic() {
|
||||
m_mediaPlayer->stop();
|
||||
}
|
28
src/qt_gui/background_music_player.h
Normal file
28
src/qt_gui/background_music_player.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QAudioOutput>
|
||||
#include <QMediaPlayer>
|
||||
#include <QObject>
|
||||
|
||||
class BackgroundMusicPlayer : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static BackgroundMusicPlayer& getInstance() {
|
||||
static BackgroundMusicPlayer instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void playMusic(const QString& snd0path);
|
||||
void stopMusic();
|
||||
|
||||
private:
|
||||
BackgroundMusicPlayer(QObject* parent = nullptr);
|
||||
|
||||
QMediaPlayer* m_mediaPlayer;
|
||||
QAudioOutput* m_audioOutput;
|
||||
QUrl m_currentMusic;
|
||||
};
|
|
@ -39,6 +39,15 @@ GameGridFrame::GameGridFrame(std::shared_ptr<GameInfoClass> game_info_get, QWidg
|
|||
});
|
||||
}
|
||||
|
||||
void GameGridFrame::PlayBackgroundMusic(QTableWidgetItem* item) {
|
||||
if (!item) {
|
||||
BackgroundMusicPlayer::getInstance().stopMusic();
|
||||
return;
|
||||
}
|
||||
const auto snd0path = QString::fromStdString(m_game_info->m_games[item->row()].snd0_path);
|
||||
BackgroundMusicPlayer::getInstance().playMusic(snd0path);
|
||||
}
|
||||
|
||||
void GameGridFrame::PopulateGameGrid(QVector<GameInfo> m_games_search, bool fromSearch) {
|
||||
QVector<GameInfo> m_games_;
|
||||
this->clearContents();
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <QScrollBar>
|
||||
|
||||
#include "background_music_player.h"
|
||||
#include "common/config.h"
|
||||
#include "game_info.h"
|
||||
#include "game_list_utils.h"
|
||||
|
@ -19,6 +20,7 @@ Q_SIGNALS:
|
|||
public Q_SLOTS:
|
||||
void SetGridBackgroundImage(int row, int column);
|
||||
void RefreshGridBackgroundImage();
|
||||
void PlayBackgroundMusic(QTableWidgetItem* item);
|
||||
|
||||
private:
|
||||
QImage backgroundImage;
|
||||
|
|
|
@ -32,6 +32,7 @@ public:
|
|||
QString iconpath = QString::fromStdString(game.icon_path);
|
||||
game.icon = QImage(iconpath);
|
||||
game.pic_path = game.path + "/sce_sys/pic1.png";
|
||||
game.snd0_path = game.path + "/sce_sys/snd0.at9";
|
||||
if (const auto title = psf.GetString("TITLE"); title.has_value()) {
|
||||
game.name = *title;
|
||||
}
|
||||
|
|
|
@ -68,6 +68,15 @@ GameListFrame::GameListFrame(std::shared_ptr<GameInfoClass> game_info_get, QWidg
|
|||
});
|
||||
}
|
||||
|
||||
void GameListFrame::PlayBackgroundMusic(QTableWidgetItem* item) {
|
||||
if (!item) {
|
||||
BackgroundMusicPlayer::getInstance().stopMusic();
|
||||
return;
|
||||
}
|
||||
const auto snd0path = QString::fromStdString(m_game_info->m_games[item->row()].snd0_path);
|
||||
BackgroundMusicPlayer::getInstance().playMusic(snd0path);
|
||||
}
|
||||
|
||||
void GameListFrame::PopulateGameList() {
|
||||
this->setRowCount(m_game_info->m_games.size());
|
||||
ResizeIcons(icon_size);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <QScrollBar>
|
||||
|
||||
#include "background_music_player.h"
|
||||
#include "game_info.h"
|
||||
#include "game_list_utils.h"
|
||||
#include "gui_context_menus.h"
|
||||
|
@ -21,6 +22,7 @@ public Q_SLOTS:
|
|||
void RefreshListBackgroundImage();
|
||||
void SortNameAscending(int columnIndex);
|
||||
void SortNameDescending(int columnIndex);
|
||||
void PlayBackgroundMusic(QTableWidgetItem* item);
|
||||
|
||||
private:
|
||||
void SetTableItem(int row, int column, QString itemStr);
|
||||
|
|
|
@ -7,6 +7,7 @@ struct GameInfo {
|
|||
std::string path; // root path of game directory (normally directory that contains eboot.bin)
|
||||
std::string icon_path; // path of icon0.png
|
||||
std::string pic_path; // path of pic1.png
|
||||
std::string snd0_path; // path of snd0.at9
|
||||
QImage icon;
|
||||
std::string size;
|
||||
// variables extracted from param.sfo
|
||||
|
|
|
@ -501,9 +501,29 @@ void MainWindow::CreateConnects() {
|
|||
isIconBlack = false;
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_game_grid_frame.get(), &QTableWidget::cellClicked, this,
|
||||
&MainWindow::PlayBackgroundMusic);
|
||||
connect(m_game_list_frame.get(), &QTableWidget::cellClicked, this,
|
||||
&MainWindow::PlayBackgroundMusic);
|
||||
}
|
||||
|
||||
void MainWindow::PlayBackgroundMusic() {
|
||||
if (isGameRunning || !Config::getPlayBGM()) {
|
||||
BackgroundMusicPlayer::getInstance().stopMusic();
|
||||
return;
|
||||
}
|
||||
int itemID = isTableList ? m_game_list_frame->currentItem()->row()
|
||||
: m_game_grid_frame->crtRow * m_game_grid_frame->columnCnt +
|
||||
m_game_grid_frame->crtColumn;
|
||||
|
||||
const auto snd0path = QString::fromStdString(m_game_info->m_games[itemID].snd0_path);
|
||||
BackgroundMusicPlayer::getInstance().playMusic(snd0path);
|
||||
}
|
||||
|
||||
void MainWindow::StartGame() {
|
||||
isGameRunning = true;
|
||||
BackgroundMusicPlayer::getInstance().stopMusic();
|
||||
QString gamePath = "";
|
||||
int table_mode = Config::getTableMode();
|
||||
if (table_mode == 0) {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <QDragEnterEvent>
|
||||
#include <QTranslator>
|
||||
|
||||
#include "background_music_player.h"
|
||||
#include "common/config.h"
|
||||
#include "common/path_util.h"
|
||||
#include "core/file_format/psf.h"
|
||||
|
@ -63,9 +64,11 @@ private:
|
|||
void BootGame();
|
||||
void AddRecentFiles(QString filePath);
|
||||
void LoadTranslation();
|
||||
void PlayBackgroundMusic();
|
||||
QIcon RecolorIcon(const QIcon& icon, bool isWhite);
|
||||
bool isIconBlack = false;
|
||||
bool isTableList = true;
|
||||
bool isGameRunning = false;
|
||||
QActionGroup* m_icon_size_act_group = nullptr;
|
||||
QActionGroup* m_list_mode_act_group = nullptr;
|
||||
QActionGroup* m_theme_act_group = nullptr;
|
||||
|
|
|
@ -134,6 +134,9 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidge
|
|||
auto checkUpdate = new CheckUpdate(true);
|
||||
checkUpdate->exec();
|
||||
});
|
||||
|
||||
connect(ui->playBGMCheckBox, &QCheckBox::stateChanged, this,
|
||||
[](int val) { Config::setPlayBGM(val); });
|
||||
}
|
||||
|
||||
// GPU TAB
|
||||
|
@ -192,7 +195,7 @@ void SettingsDialog::LoadValuesFromConfig() {
|
|||
ui->dumpShadersCheckBox->setChecked(Config::dumpShaders());
|
||||
ui->nullGpuCheckBox->setChecked(Config::nullGpu());
|
||||
ui->dumpPM4CheckBox->setChecked(Config::dumpPM4());
|
||||
|
||||
ui->playBGMCheckBox->setChecked(Config::getPlayBGM());
|
||||
ui->fullscreenCheckBox->setChecked(Config::isFullscreenMode());
|
||||
ui->showSplashCheckBox->setChecked(Config::showSplash());
|
||||
ui->ps4proCheckBox->setChecked(Config::isNeoMode());
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>836</width>
|
||||
<height>428</height>
|
||||
<height>432</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -70,7 +70,7 @@
|
|||
</attribute>
|
||||
<layout class="QVBoxLayout" name="generalTabVLayout" stretch="0,0">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="generalTabHLayout" stretch="1,1,1">
|
||||
<layout class="QHBoxLayout" name="generalTabHLayoutTop" stretch="1,1,1">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="systemTabLayoutLeft">
|
||||
<item>
|
||||
|
@ -340,19 +340,55 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="GUITabLayoutMiddle" stretch="1">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="GUIgroupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>GUI Settings</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="verticalLayoutWidget_3">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>30</y>
|
||||
<width>241</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="playBGMCheckBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Play title music</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>500</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
<enum>QSizePolicy::Policy::Expanding</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
|
|
Loading…
Reference in a new issue