mirror of
https://github.com/Fluorohydride/ygopro.git
synced 2026-10-17 05:20:57 +08:00
343 lines
8.3 KiB
C++
343 lines
8.3 KiB
C++
#include "sound_manager.h"
|
|
#include "myfilesystem.h"
|
|
#if defined(YGOPRO_USE_MINIAUDIO) && defined(YGOPRO_MINIAUDIO_SUPPORT_OPUS_VORBIS)
|
|
#include <miniaudio_libopus.h>
|
|
#include <miniaudio_libvorbis.h>
|
|
#endif
|
|
#ifdef IRRKLANG_STATIC
|
|
#include "../ikpmp3/ikpMP3.h"
|
|
#endif
|
|
|
|
namespace ygo {
|
|
|
|
SoundManager soundManager;
|
|
|
|
bool SoundManager::Init() {
|
|
#ifdef YGOPRO_USE_AUDIO
|
|
bgm_scene = -1;
|
|
RefreshBGMList();
|
|
rnd.seed(std::random_device()());
|
|
#ifdef YGOPRO_USE_MINIAUDIO
|
|
engineConfig = ma_engine_config_init();
|
|
#ifdef YGOPRO_MINIAUDIO_SUPPORT_OPUS_VORBIS
|
|
ma_decoding_backend_vtable* pCustomBackendVTables[] =
|
|
{
|
|
ma_decoding_backend_libvorbis,
|
|
ma_decoding_backend_libopus
|
|
};
|
|
resourceManagerConfig = ma_resource_manager_config_init();
|
|
resourceManagerConfig.ppCustomDecodingBackendVTables = pCustomBackendVTables;
|
|
resourceManagerConfig.customDecodingBackendCount = sizeof(pCustomBackendVTables) / sizeof(pCustomBackendVTables[0]);
|
|
resourceManagerConfig.pCustomDecodingBackendUserData = NULL;
|
|
if(ma_resource_manager_init(&resourceManagerConfig, &resourceManager) != MA_SUCCESS) {
|
|
return false;
|
|
}
|
|
engineConfig.pResourceManager = &resourceManager;
|
|
#endif
|
|
if(ma_engine_init(&engineConfig, &engineSound) != MA_SUCCESS || ma_engine_init(&engineConfig, &engineMusic) != MA_SUCCESS) {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
#endif // YGOPRO_USE_MINIAUDIO
|
|
#ifdef YGOPRO_USE_IRRKLANG
|
|
engineSound = irrklang::createIrrKlangDevice();
|
|
engineMusic = irrklang::createIrrKlangDevice();
|
|
if(!engineSound || !engineMusic) {
|
|
return false;
|
|
} else {
|
|
#ifdef IRRKLANG_STATIC
|
|
irrklang::ikpMP3Init(engineMusic);
|
|
#endif
|
|
return true;
|
|
}
|
|
#endif // YGOPRO_USE_IRRKLANG
|
|
#endif // YGOPRO_USE_AUDIO
|
|
return false;
|
|
}
|
|
void SoundManager::RefreshBGMList() {
|
|
#ifdef YGOPRO_USE_AUDIO
|
|
RefershBGMDir(L"", BGM_DUEL);
|
|
RefershBGMDir(L"duel", BGM_DUEL);
|
|
RefershBGMDir(L"menu", BGM_MENU);
|
|
RefershBGMDir(L"deck", BGM_DECK);
|
|
RefershBGMDir(L"advantage", BGM_ADVANTAGE);
|
|
RefershBGMDir(L"disadvantage", BGM_DISADVANTAGE);
|
|
RefershBGMDir(L"win", BGM_WIN);
|
|
RefershBGMDir(L"lose", BGM_LOSE);
|
|
#endif
|
|
}
|
|
void SoundManager::RefershBGMDir(std::wstring path, int scene) {
|
|
#ifdef YGOPRO_USE_AUDIO
|
|
std::wstring search = L"./sound/BGM/" + path;
|
|
FileSystem::TraversalDir(search.c_str(), [this, &path, scene](const wchar_t* name, bool isdir) {
|
|
if(!isdir && (
|
|
IsExtension(name, L".mp3")
|
|
#if defined(YGOPRO_MINIAUDIO_SUPPORT_OPUS_VORBIS) || defined(YGOPRO_USE_IRRKLANG)
|
|
|| IsExtension(name, L".ogg")
|
|
#endif
|
|
)) {
|
|
std::wstring filename = path + L"/" + name;
|
|
BGMList[BGM_ALL].push_back(filename);
|
|
BGMList[scene].push_back(filename);
|
|
}
|
|
});
|
|
#endif // YGOPRO_USE_AUDIO
|
|
}
|
|
void SoundManager::PlaySoundEffect(int sound) {
|
|
#ifdef YGOPRO_USE_AUDIO
|
|
if(!mainGame->chkEnableSound->isChecked())
|
|
return;
|
|
char soundName[32];
|
|
switch(sound) {
|
|
case SOUND_SUMMON: {
|
|
strcpy(soundName, "summon");
|
|
break;
|
|
}
|
|
case SOUND_SPECIAL_SUMMON: {
|
|
strcpy(soundName, "specialsummon");
|
|
break;
|
|
}
|
|
case SOUND_ACTIVATE: {
|
|
strcpy(soundName, "activate");
|
|
break;
|
|
}
|
|
case SOUND_SET: {
|
|
strcpy(soundName, "set");
|
|
break;
|
|
}
|
|
case SOUND_FILP: {
|
|
strcpy(soundName, "flip");
|
|
break;
|
|
}
|
|
case SOUND_REVEAL: {
|
|
strcpy(soundName, "reveal");
|
|
break;
|
|
}
|
|
case SOUND_EQUIP: {
|
|
strcpy(soundName, "equip");
|
|
break;
|
|
}
|
|
case SOUND_DESTROYED: {
|
|
strcpy(soundName, "destroyed");
|
|
break;
|
|
}
|
|
case SOUND_BANISHED: {
|
|
strcpy(soundName, "banished");
|
|
break;
|
|
}
|
|
case SOUND_TOKEN: {
|
|
strcpy(soundName, "token");
|
|
break;
|
|
}
|
|
case SOUND_NEGATE: {
|
|
strcpy(soundName, "negate");
|
|
break;
|
|
}
|
|
case SOUND_ATTACK: {
|
|
strcpy(soundName, "attack");
|
|
break;
|
|
}
|
|
case SOUND_DIRECT_ATTACK: {
|
|
strcpy(soundName, "directattack");
|
|
break;
|
|
}
|
|
case SOUND_DRAW: {
|
|
strcpy(soundName, "draw");
|
|
break;
|
|
}
|
|
case SOUND_SHUFFLE: {
|
|
strcpy(soundName, "shuffle");
|
|
break;
|
|
}
|
|
case SOUND_DAMAGE: {
|
|
strcpy(soundName, "damage");
|
|
break;
|
|
}
|
|
case SOUND_RECOVER: {
|
|
strcpy(soundName, "gainlp");
|
|
break;
|
|
}
|
|
case SOUND_COUNTER_ADD: {
|
|
strcpy(soundName, "addcounter");
|
|
break;
|
|
}
|
|
case SOUND_COUNTER_REMOVE: {
|
|
strcpy(soundName, "removecounter");
|
|
break;
|
|
}
|
|
case SOUND_COIN: {
|
|
strcpy(soundName, "coinflip");
|
|
break;
|
|
}
|
|
case SOUND_DICE: {
|
|
strcpy(soundName, "diceroll");
|
|
break;
|
|
}
|
|
case SOUND_NEXT_TURN: {
|
|
strcpy(soundName, "nextturn");
|
|
break;
|
|
}
|
|
case SOUND_PHASE: {
|
|
strcpy(soundName, "phase");
|
|
break;
|
|
}
|
|
case SOUND_MENU: {
|
|
strcpy(soundName, "menu");
|
|
break;
|
|
}
|
|
case SOUND_BUTTON: {
|
|
strcpy(soundName, "button");
|
|
break;
|
|
}
|
|
case SOUND_INFO: {
|
|
strcpy(soundName, "info");
|
|
break;
|
|
}
|
|
case SOUND_QUESTION: {
|
|
strcpy(soundName, "question");
|
|
break;
|
|
}
|
|
case SOUND_CARD_PICK: {
|
|
strcpy(soundName, "cardpick");
|
|
break;
|
|
}
|
|
case SOUND_CARD_DROP: {
|
|
strcpy(soundName, "carddrop");
|
|
break;
|
|
}
|
|
case SOUND_PLAYER_ENTER: {
|
|
strcpy(soundName, "playerenter");
|
|
break;
|
|
}
|
|
case SOUND_CHAT: {
|
|
strcpy(soundName, "chatmessage");
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
char soundPath[40];
|
|
std::snprintf(soundPath, 40, "./sound/%s.wav", soundName);
|
|
SetSoundVolume(mainGame->gameConf.sound_volume);
|
|
#ifdef YGOPRO_USE_MINIAUDIO
|
|
ma_engine_play_sound(&engineSound, soundPath, nullptr);
|
|
#endif
|
|
#ifdef YGOPRO_USE_IRRKLANG
|
|
engineSound->play2D(soundPath);
|
|
#endif
|
|
#endif // YGOPRO_USE_AUDIO
|
|
}
|
|
void SoundManager::PlayDialogSound(irr::gui::IGUIElement * element) {
|
|
#ifdef YGOPRO_USE_AUDIO
|
|
if(element == mainGame->wMessage) {
|
|
PlaySoundEffect(SOUND_INFO);
|
|
} else if(element == mainGame->wQuery) {
|
|
PlaySoundEffect(SOUND_QUESTION);
|
|
} else if(element == mainGame->wSurrender) {
|
|
PlaySoundEffect(SOUND_QUESTION);
|
|
} else if(element == mainGame->wOptions) {
|
|
PlaySoundEffect(SOUND_QUESTION);
|
|
} else if(element == mainGame->wANAttribute) {
|
|
PlaySoundEffect(SOUND_QUESTION);
|
|
} else if(element == mainGame->wANCard) {
|
|
PlaySoundEffect(SOUND_QUESTION);
|
|
} else if(element == mainGame->wANNumber) {
|
|
PlaySoundEffect(SOUND_QUESTION);
|
|
} else if(element == mainGame->wANRace) {
|
|
PlaySoundEffect(SOUND_QUESTION);
|
|
} else if(element == mainGame->wReplaySave) {
|
|
PlaySoundEffect(SOUND_QUESTION);
|
|
} else if(element == mainGame->wFTSelect) {
|
|
PlaySoundEffect(SOUND_QUESTION);
|
|
}
|
|
#endif // YGOPRO_USE_AUDIO
|
|
}
|
|
bool SoundManager::IsPlayingMusic(wchar_t* music) {
|
|
#ifdef YGOPRO_USE_MINIAUDIO
|
|
if(music) {
|
|
return !mywcsncasecmp(currentPlayingMusic, music, 1024) && ma_sound_is_playing(&soundBGM);
|
|
} else {
|
|
return ma_sound_is_playing(&soundBGM);
|
|
}
|
|
#endif
|
|
#ifdef YGOPRO_USE_IRRKLANG
|
|
if(music) {
|
|
char cmusic[1024];
|
|
BufferIO::EncodeUTF8(music, cmusic);
|
|
return engineMusic->isCurrentlyPlaying(cmusic);
|
|
} else {
|
|
return soundBGM && !soundBGM->isFinished();
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
void SoundManager::PlayMusic(wchar_t* music, bool loop) {
|
|
#ifdef YGOPRO_USE_AUDIO
|
|
if(!mainGame->chkEnableMusic->isChecked())
|
|
return;
|
|
if(!IsPlayingMusic(music)) {
|
|
StopBGM();
|
|
SetMusicVolume(mainGame->gameConf.music_volume);
|
|
#ifdef YGOPRO_USE_MINIAUDIO
|
|
BufferIO::CopyWStr(music, currentPlayingMusic, 1024);
|
|
ma_sound_init_from_file_w(&engineMusic, music, MA_SOUND_FLAG_ASYNC | MA_SOUND_FLAG_STREAM, nullptr, nullptr, &soundBGM);
|
|
ma_sound_set_looping(&soundBGM, loop);
|
|
ma_sound_start(&soundBGM);
|
|
#endif
|
|
#ifdef YGOPRO_USE_IRRKLANG
|
|
char cmusic[1024];
|
|
BufferIO::EncodeUTF8(music, cmusic);
|
|
soundBGM = engineMusic->play2D(cmusic, loop, false, true);
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
void SoundManager::PlayBGM(int scene) {
|
|
#ifdef YGOPRO_USE_AUDIO
|
|
if(!mainGame->chkEnableMusic->isChecked())
|
|
return;
|
|
if(!mainGame->chkMusicMode->isChecked())
|
|
scene = BGM_ALL;
|
|
if(scene != bgm_scene || !IsPlayingMusic()) {
|
|
int count = BGMList[scene].size();
|
|
if(count <= 0)
|
|
return;
|
|
bgm_scene = scene;
|
|
int bgm = (count > 1) ? std::uniform_int_distribution<>(0, count - 1)(rnd) : 0;
|
|
auto name = BGMList[scene][bgm].c_str();
|
|
wchar_t BGMName[1024];
|
|
myswprintf(BGMName, L"./sound/BGM/%ls", name);
|
|
PlayMusic(BGMName, false);
|
|
}
|
|
#endif
|
|
}
|
|
void SoundManager::StopBGM() {
|
|
#ifdef YGOPRO_USE_MINIAUDIO
|
|
if(!currentPlayingMusic[0])
|
|
return;
|
|
memset(currentPlayingMusic, 0, sizeof(currentPlayingMusic));
|
|
ma_sound_uninit(&soundBGM);
|
|
#endif
|
|
#ifdef YGOPRO_USE_IRRKLANG
|
|
engineMusic->stopAllSounds();
|
|
#endif
|
|
}
|
|
void SoundManager::SetSoundVolume(double volume) {
|
|
#ifdef YGOPRO_USE_MINIAUDIO
|
|
ma_engine_set_volume(&engineSound, volume);
|
|
#endif
|
|
#ifdef YGOPRO_USE_IRRKLANG
|
|
engineSound->setSoundVolume(volume);
|
|
#endif
|
|
}
|
|
void SoundManager::SetMusicVolume(double volume) {
|
|
#ifdef YGOPRO_USE_MINIAUDIO
|
|
ma_engine_set_volume(&engineMusic, volume);
|
|
#endif
|
|
#ifdef YGOPRO_USE_IRRKLANG
|
|
engineMusic->setSoundVolume(volume);
|
|
#endif
|
|
}
|
|
}
|