Make loading for BGMs loopless.

pull/35/head
sigonasr2 11 months ago
parent 42d4e794c7
commit 76c1487871
  1. 20
      Adventures in Lestoria/AdventuresInLestoria.cpp
  2. 94
      Adventures in Lestoria/Audio.cpp
  3. 15
      Adventures in Lestoria/Audio.h
  4. 6
      Adventures in Lestoria/LoadingScreen.cpp
  5. 2
      Adventures in Lestoria/LoadingScreen.h
  6. 2
      Adventures in Lestoria/Version.h
  7. BIN
      x64/Release/Adventures in Lestoria.exe

@ -1823,6 +1823,7 @@ void AiL::InitializeLevel(std::string mapFile,MapName map){
void AiL::LoadLevel(MapName map){
LoadingScreen::loading=true;
#pragma region Reset all data (Loading phase 1)
if(game->MAP_DATA.count(map)==0)ERR(std::format("WARNING! Could not load map {}! Does not exist! Refer to levels.txt for valid maps.",map));
if(game->MAP_DATA[map].GetMapType()=="Hub"&&GameState::STATE!=GameState::states[States::GAME_HUB])ERR("WARNING! A hub level should only be initiated in the GAME_HUB game state!");
@ -1857,9 +1858,11 @@ void AiL::LoadLevel(MapName map){
GetPlayer()->GetCastInfo()={};
GetPlayer()->ResetAccumulatedXP();
#pragma endregion
ZONE_LIST=game->MAP_DATA[game->GetCurrentLevel()].ZoneData;
#pragma region Monster Spawn Data Setup
#pragma region Monster Spawn Data Setup (Loading phase 2)
for(auto&[key,value]:MAP_DATA[map].SpawnerData){
SpawnerTag&spawnData=MAP_DATA[map].SpawnerData[key];
std::vector<std::pair<std::string,vf2d>>monster_list;
@ -1873,7 +1876,7 @@ void AiL::LoadLevel(MapName map){
}
#pragma endregion
#pragma region Identify Upper Foreground Tiles
#pragma region Identify Upper Foreground Tiles (Loading phase 3)
auto GetUpperZones=[&](){
for(auto&zoneSet:MAP_DATA[map].ZoneData){
if(zoneSet.first=="UpperZone"){ //We are interested in all upper zones.
@ -1902,7 +1905,7 @@ void AiL::LoadLevel(MapName map){
}
#pragma endregion
#pragma region Foreground and Upper Foreground Tile Fade Group Setup
#pragma region Foreground and Upper Foreground Tile Fade Group Setup (Loading phase 4)
std::set<vi2d>foregroundTilesAdded,upperForegroundTilesAdded;
for(int x=0;x<GetCurrentMapData().width;x++){
for(int y=0;y<GetCurrentMapData().height;y++){
@ -1992,7 +1995,7 @@ void AiL::LoadLevel(MapName map){
}
#pragma endregion
#pragma region Foreground and Upper Foreground Tile Fade Group Individual Object Grouping Splitting
#pragma region Foreground and Upper Foreground Tile Fade Group Individual Object Grouping Splitting (Loading phase 5)
auto SplitUp=[&](std::vector<TileGroup>&group){
std::multimap<vi2d,TileRenderData>data;
using TileDataGroup=std::multimap<vi2d,TileRenderData>; //See below.
@ -2059,7 +2062,7 @@ void AiL::LoadLevel(MapName map){
SplitUp(upperForegroundTileGroups);
#pragma endregion
#pragma region Bridge Layer Setup
#pragma region Bridge Layer Setup (Loading Phase 6)
bridgeLayerIndex=-1;
for(int counter=0;LayerTag&layer:MAP_DATA[map].LayerData){
if(IsBridgeLayer(layer)){
@ -2069,6 +2072,7 @@ void AiL::LoadLevel(MapName map){
}
#pragma endregion
#pragma region Setup NPCs (Loading Phase 7)
for(NPCData data:game->MAP_DATA[game->GetCurrentLevel()].npcs){
if(Unlock::IsUnlocked(data.unlockCondition)){
MONSTER_LIST.push_back(Monster{data.spawnPos,MONSTER_DATA[data.name]});
@ -2076,7 +2080,9 @@ void AiL::LoadLevel(MapName map){
MONSTER_LIST.back().npcData=data;
}
}
#pragma endregion
#pragma region Setup Player and Camera (Loading Phase 8)
player->GetAbility1().cooldown=0.f;
player->GetAbility2().cooldown=0.f;
player->GetAbility3().cooldown=0.f;
@ -2091,8 +2097,12 @@ void AiL::LoadLevel(MapName map){
vf2d cameraStartPos=player->GetPos()+vf2d(-24*6,0);
camera.MoveCamera(cameraStartPos);
#pragma endregion
#pragma region Setup Pathfinding (Loading Phase 9)
pathfinder.Initialize();
#pragma endregion
Audio::SetAudioEvent("Default Volume");
game->audioEngine.fullyLoaded=true; //We assume there's no audio to load, so we just set the audio as fully loaded by default.
if(MAP_DATA[map].bgmSongName.length()>0){

@ -39,6 +39,7 @@ All rights reserved.
#include "AdventuresInLestoria.h"
#include "DEFINES.h"
#include "util.h"
#include "LoadingScreen.h"
INCLUDE_game
INCLUDE_DATA
@ -121,12 +122,21 @@ const size_t Audio::LoadAndPlay(const std::string_view sound,const bool loop){
Engine().Play(soundID,loop);
return soundID;
};
void Audio::PlayBGM(const std::string_view sound,const bool loop){
void Audio::PrepareBGM(const std::string_view sound,const bool loop){
BGM&track=Self().bgm[std::string(sound)];
Self().fullyLoaded=false;
StopBGM(); //Stop any currently playing track.
Self().playParams={std::string(sound),loop};
Self().playBGMWaitTime=0.7f;
#pragma region Internal Loading Loop Setup
Self().trackLoadStarted=false;
Self().trackLoadComplete=false;
Self().channelPlayingStarted=false;
Self().channelPlayingComplete=false;
int currentLoopIndex=0;
#pragma endregion
Self().immediatelyLoadAudio=false;
};
void Audio::StopBGM(){
@ -142,24 +152,35 @@ const bool Audio::BGMIsPlaying(){
return Self().currentBGM.length()>0;
}
const Volume&Audio::BGM::GetVolume(const Event&eventName,const ChannelID&id)const{
return eventVolumes.GetVolumes(eventName).at(id);
const Volume&Audio::BGM::GetVolume(const Event&eventName,const int&index)const{
return eventVolumes.GetVolumes(eventName).at(index);
}
void Audio::BGM::Load(){
if(Self().BGMIsPlaying()){
if(Self().GetTrackName()==songFileName)return; //We are already playing the current track.
BGM&bgm=Self().bgm[Self().GetTrackName()];
if(!Self().trackLoadStarted){
Self().trackLoadStarted=true;
if(Self().BGMIsPlaying()){
bgm.Unload();
if(Self().GetTrackName()==songFileName)return; //We are already playing the current track.
BGM&bgm=Self().bgm[Self().GetTrackName()];
if(Self().BGMIsPlaying()){
bgm.Unload();
}
}
}
Self().currentBGM=songFileName;
BGM&newBgm=Self().bgm[songFileName];
if(newBgm.channels.size()>0)ERR(std::format("WARNING! The size of the channels list is greater than zero! Size: {}",newBgm.channels.size()));
for(const ChannelName&channel:newBgm.GetChannels()){
Self().currentBGM=songFileName;
Self().currentLoopIndex=0;
BGM&newBgm=Self().bgm[songFileName];
if(newBgm.channels.size()>0)ERR(std::format("WARNING! The size of the channels list is greater than zero! Size: {}",newBgm.channels.size()));
}else{
BGM&newBgm=Self().bgm[songFileName];
const ChannelName&channel=newBgm.GetChannels()[Self().currentLoopIndex];
ChannelID soundID=Engine().LoadSound("bgm_directory"_S+channel);
newBgm.channels.push_back(soundID);
#pragma region Handle threaded loop indexing
Self().currentLoopIndex++;
if(Self().currentLoopIndex>=newBgm.GetChannels().size()){
Self().trackLoadComplete=true;
}
#pragma endregion
}
}
@ -255,27 +276,54 @@ const SongName&Audio::GetTrackName(){
return Self().currentBGM;
}
void Audio::Update(){
if(Self().playBGMWaitTime>0.f){
Self().playBGMWaitTime=std::max(Self().playBGMWaitTime-game->GetElapsedTime(),0.f);
if(Self().playBGMWaitTime==0.f){
BGM&track=Self().bgm[Self().playParams.sound];
void Audio::UpdateLoop(){
if(Self().playBGMWaitTime==0.f){
BGM&track=Self().bgm[Self().playParams.sound];
if(!Self().trackLoadComplete){
track.Load();
Self().prevVolumes.clear();
Self().targetVolumes.clear();
Self().fadeToTargetVolumeTime=0.f;
for(int channelListIndex=0;int trackID:track.GetChannelIDs()){
float channelVol=track.GetVolume(Self().currentAudioEvent,channelListIndex);
}else
if(!Self().channelPlayingComplete){
if(!Self().channelPlayingStarted){
Self().prevVolumes.clear();
Self().targetVolumes.clear();
Self().fadeToTargetVolumeTime=0.f;
Self().currentLoopIndex=0;
Self().channelPlayingStarted=true;
}else{
int trackID=track.GetChannelIDs()[Self().currentLoopIndex];
float channelVol=track.GetVolume(Self().currentAudioEvent,Self().currentLoopIndex);
Self().prevVolumes.push_back(channelVol);
Self().targetVolumes.push_back(channelVol);
Engine().SetVolume(trackID,channelVol*GetBGMVolume());
Engine().Play(trackID,Self().playParams.loop);
channelListIndex++;
#pragma region Handle threaded loop indexing
Self().currentLoopIndex++;
if(Self().currentLoopIndex>=track.GetChannelIDs().size()){
Self().channelPlayingComplete=true;
}
#pragma endregion
}
}else{
Self().fullyLoaded=true;
}
}
}
void Audio::PlayBGM(const std::string_view sound,const bool loop){
PrepareBGM(sound,loop);
Self().immediatelyLoadAudio=true;
}
void Audio::Update(){
if(Self().playBGMWaitTime>0.f){
Self().playBGMWaitTime=std::max(Self().playBGMWaitTime-game->GetElapsedTime(),0.f);
if(Self().playBGMWaitTime==0.f&&Self().immediatelyLoadAudio){
while(!Self().BGMFullyLoaded()){
UpdateLoop(); //We immediately load the file. In a loading screen setting we would defer UpdateLoop() such that we have extra time to update the screen, UpdateLoop() is divided into many parts of the music loading process.
}
}
}
if(Self().fadeToTargetVolumeTime>0.f){
Self().fadeToTargetVolumeTime=std::max(0.f,Self().fadeToTargetVolumeTime-game->GetElapsedTime());
for(int counter=0;float&vol:Self().prevVolumes){

@ -56,10 +56,13 @@ public:
static MiniAudio&Engine();
static void Initialize();
static void Update();
static void UpdateLoop();
static void Play(const std::string_view sound);
[[nodiscard]]
static const size_t LoadAndPlay(const std::string_view sound,const bool loop=true);
//Play a BGM given a name found in bgm.txt configuration file.
//Prepares a BGM for loading. This means we call UpdateLoop() repeatedly until the loading of the music is complete. Names are found in bgm.txt configuration file.
static void PrepareBGM(const std::string_view sound,const bool loop=true);
//Play immediately a BGM given a name found in bgm.txt configuration file.
static void PlayBGM(const std::string_view sound,const bool loop=true);
static void StopBGM();
static const Event&GetAudioEvent();
@ -73,6 +76,14 @@ public:
static float&GetSFXVolume();
static float GetMuteMult();
private:
bool trackLoadStarted=false;
bool trackLoadComplete=false;
bool channelPlayingStarted=false;
bool channelPlayingComplete=false;
int currentLoopIndex=0;
//Set to false by PrepareBGM(). If PlayBGM() is called instead, it will set the state of this variable to true, such that the loading is performed in Audio::Update()!
bool immediatelyLoadAudio=false;
struct BGMPlayParams{
std::string sound;
bool loop;
@ -92,7 +103,7 @@ private:
const size_t GetChannelCount()const;
const std::vector<ChannelName>&GetChannels()const;
const SongName&GetName()const;
const Volume&GetVolume(const Event&eventName,const ChannelID&id)const;
const Volume&GetVolume(const Event&eventName,const int&index)const;
void SetName(std::string_view name);
void SetFileName(std::string_view name);
void AddChannel(const ChannelName&name);

@ -45,10 +45,14 @@ INCLUDE_WINDOW_SIZE
bool LoadingScreen::loading=false;
int LoadingScreen::totalProgress=0;
int LoadingScreen::currentProgress=0;
float LoadingScreen::waitTime=0.01f;
void LoadingScreen::DeferLoad(float waitTime){
}
void LoadingScreen::Update(){
if(loading){
}
}
void LoadingScreen::Draw(){

@ -42,6 +42,8 @@ public:
static bool loading;
static int totalProgress;
static int currentProgress;
static float waitTime;
static void Update();
static void Draw();
static void DeferLoad(float waitTime);
};

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 0
#define VERSION_MINOR 3
#define VERSION_PATCH 0
#define VERSION_BUILD 7521
#define VERSION_BUILD 7526
#define stringify(a) stringify_(a)
#define stringify_(a) #a

Loading…
Cancel
Save