|
|
@ -26,14 +26,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
#include "../mwmechanics/actorutil.hpp"
|
|
|
|
#include "../mwmechanics/actorutil.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "constants.hpp"
|
|
|
|
|
|
|
|
#include "ffmpeg_decoder.hpp"
|
|
|
|
|
|
|
|
#include "openal_output.hpp"
|
|
|
|
#include "sound.hpp"
|
|
|
|
#include "sound.hpp"
|
|
|
|
#include "sound_buffer.hpp"
|
|
|
|
#include "sound_buffer.hpp"
|
|
|
|
#include "sound_decoder.hpp"
|
|
|
|
#include "sound_decoder.hpp"
|
|
|
|
#include "sound_output.hpp"
|
|
|
|
#include "sound_output.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
#include "ffmpeg_decoder.hpp"
|
|
|
|
|
|
|
|
#include "openal_output.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace MWSound
|
|
|
|
namespace MWSound
|
|
|
|
{
|
|
|
|
{
|
|
|
|
namespace
|
|
|
|
namespace
|
|
|
@ -252,13 +252,13 @@ namespace MWSound
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SoundManager::streamMusicFull(const std::string& filename)
|
|
|
|
void SoundManager::streamMusicFull(VFS::Path::NormalizedView filename)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (!mOutput->isInitialized())
|
|
|
|
if (!mOutput->isInitialized())
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
stopMusic();
|
|
|
|
stopMusic();
|
|
|
|
if (filename.empty())
|
|
|
|
if (filename.value().empty())
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
Log(Debug::Info) << "Playing \"" << filename << "\"";
|
|
|
|
Log(Debug::Info) << "Playing \"" << filename << "\"";
|
|
|
@ -269,7 +269,7 @@ namespace MWSound
|
|
|
|
{
|
|
|
|
{
|
|
|
|
decoder->open(filename);
|
|
|
|
decoder->open(filename);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (std::exception& e)
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Log(Debug::Error) << "Failed to load audio from \"" << filename << "\": " << e.what();
|
|
|
|
Log(Debug::Error) << "Failed to load audio from \"" << filename << "\": " << e.what();
|
|
|
|
return;
|
|
|
|
return;
|
|
|
@ -285,7 +285,7 @@ namespace MWSound
|
|
|
|
mOutput->streamSound(std::move(decoder), mMusic.get());
|
|
|
|
mOutput->streamSound(std::move(decoder), mMusic.get());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SoundManager::advanceMusic(const std::string& filename, float fadeOut)
|
|
|
|
void SoundManager::advanceMusic(VFS::Path::NormalizedView filename, float fadeOut)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (!isMusicPlaying())
|
|
|
|
if (!isMusicPlaying())
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -300,13 +300,16 @@ namespace MWSound
|
|
|
|
|
|
|
|
|
|
|
|
void SoundManager::startRandomTitle()
|
|
|
|
void SoundManager::startRandomTitle()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const std::vector<std::string>& filelist = mMusicFiles[mCurrentPlaylist];
|
|
|
|
const auto playlist = mMusicFiles.find(mCurrentPlaylist);
|
|
|
|
if (filelist.empty())
|
|
|
|
|
|
|
|
|
|
|
|
if (playlist == mMusicFiles.end() || playlist->second.empty())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
advanceMusic(std::string());
|
|
|
|
advanceMusic(VFS::Path::NormalizedView());
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const std::vector<VFS::Path::Normalized>& filelist = playlist->second;
|
|
|
|
|
|
|
|
|
|
|
|
auto& tracklist = mMusicToPlay[mCurrentPlaylist];
|
|
|
|
auto& tracklist = mMusicToPlay[mCurrentPlaylist];
|
|
|
|
|
|
|
|
|
|
|
|
// Do a Fisher-Yates shuffle
|
|
|
|
// Do a Fisher-Yates shuffle
|
|
|
@ -335,7 +338,7 @@ namespace MWSound
|
|
|
|
return mMusic && mOutput->isStreamPlaying(mMusic.get());
|
|
|
|
return mMusic && mOutput->isStreamPlaying(mMusic.get());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SoundManager::streamMusic(const std::string& filename, MusicType type, float fade)
|
|
|
|
void SoundManager::streamMusic(VFS::Path::NormalizedView filename, MusicType type, float fade)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const auto mechanicsManager = MWBase::Environment::get().getMechanicsManager();
|
|
|
|
const auto mechanicsManager = MWBase::Environment::get().getMechanicsManager();
|
|
|
|
|
|
|
|
|
|
|
@ -344,35 +347,36 @@ namespace MWSound
|
|
|
|
&& type != MusicType::Special)
|
|
|
|
&& type != MusicType::Special)
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
std::string normalizedName = VFS::Path::normalizeFilename(filename);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mechanicsManager->setMusicType(type);
|
|
|
|
mechanicsManager->setMusicType(type);
|
|
|
|
advanceMusic(normalizedName, fade);
|
|
|
|
advanceMusic(filename, fade);
|
|
|
|
if (type == MWSound::MusicType::Battle)
|
|
|
|
if (type == MWSound::MusicType::Battle)
|
|
|
|
mCurrentPlaylist = "Battle";
|
|
|
|
mCurrentPlaylist = battlePlaylist;
|
|
|
|
else if (type == MWSound::MusicType::Explore)
|
|
|
|
else if (type == MWSound::MusicType::Explore)
|
|
|
|
mCurrentPlaylist = "Explore";
|
|
|
|
mCurrentPlaylist = explorePlaylist;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SoundManager::playPlaylist(const std::string& playlist)
|
|
|
|
void SoundManager::playPlaylist(VFS::Path::NormalizedView playlist)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (mCurrentPlaylist == playlist)
|
|
|
|
if (mCurrentPlaylist == playlist)
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (mMusicFiles.find(playlist) == mMusicFiles.end())
|
|
|
|
auto it = mMusicFiles.find(playlist);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (it == mMusicFiles.end())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
std::vector<std::string> filelist;
|
|
|
|
std::vector<VFS::Path::Normalized> filelist;
|
|
|
|
auto playlistPath = Misc::ResourceHelpers::correctMusicPath(playlist) + '/';
|
|
|
|
const VFS::Path::Normalized playlistPath
|
|
|
|
for (const auto& name : mVFS->getRecursiveDirectoryIterator(playlistPath))
|
|
|
|
= Misc::ResourceHelpers::correctMusicPath(playlist) / VFS::Path::NormalizedView();
|
|
|
|
|
|
|
|
for (const auto& name : mVFS->getRecursiveDirectoryIterator(VFS::Path::NormalizedView(playlistPath)))
|
|
|
|
filelist.push_back(name);
|
|
|
|
filelist.push_back(name);
|
|
|
|
|
|
|
|
|
|
|
|
mMusicFiles[playlist] = std::move(filelist);
|
|
|
|
it = mMusicFiles.emplace_hint(it, playlist, std::move(filelist));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// No Battle music? Use Explore playlist
|
|
|
|
// No Battle music? Use Explore playlist
|
|
|
|
if (playlist == "Battle" && mMusicFiles[playlist].empty())
|
|
|
|
if (playlist == battlePlaylist && it->second.empty())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
playPlaylist("Explore");
|
|
|
|
playPlaylist(explorePlaylist);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -1019,7 +1023,7 @@ namespace MWSound
|
|
|
|
mTimePassed = 0.0f;
|
|
|
|
mTimePassed = 0.0f;
|
|
|
|
|
|
|
|
|
|
|
|
// Make sure music is still playing
|
|
|
|
// Make sure music is still playing
|
|
|
|
if (!isMusicPlaying() && !mCurrentPlaylist.empty())
|
|
|
|
if (!isMusicPlaying() && !mCurrentPlaylist.value().empty())
|
|
|
|
startRandomTitle();
|
|
|
|
startRandomTitle();
|
|
|
|
|
|
|
|
|
|
|
|
Environment env = Env_Normal;
|
|
|
|
Environment env = Env_Normal;
|
|
|
@ -1137,10 +1141,10 @@ namespace MWSound
|
|
|
|
if (!mMusic || !mMusic->updateFade(duration) || !mOutput->isStreamPlaying(mMusic.get()))
|
|
|
|
if (!mMusic || !mMusic->updateFade(duration) || !mOutput->isStreamPlaying(mMusic.get()))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
stopMusic();
|
|
|
|
stopMusic();
|
|
|
|
if (!mNextMusic.empty())
|
|
|
|
if (!mNextMusic.value().empty())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
streamMusicFull(mNextMusic);
|
|
|
|
streamMusicFull(mNextMusic);
|
|
|
|
mNextMusic.clear();
|
|
|
|
mNextMusic = VFS::Path::Normalized();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
else
|
|
|
@ -1160,9 +1164,8 @@ namespace MWSound
|
|
|
|
|
|
|
|
|
|
|
|
if (isMainMenu && !isMusicPlaying())
|
|
|
|
if (isMainMenu && !isMusicPlaying())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
std::string titlefile = "music/special/morrowind title.mp3";
|
|
|
|
if (mVFS->exists(MWSound::titleMusic))
|
|
|
|
if (mVFS->exists(titlefile))
|
|
|
|
streamMusic(MWSound::titleMusic, MWSound::MusicType::Special);
|
|
|
|
streamMusic(titlefile, MWSound::MusicType::Special);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
updateSounds(duration);
|
|
|
|
updateSounds(duration);
|
|
|
|