diff --git a/Adventures in Lestoria/Audio.cpp b/Adventures in Lestoria/Audio.cpp index c80da7b2..7084a4be 100644 --- a/Adventures in Lestoria/Audio.cpp +++ b/Adventures in Lestoria/Audio.cpp @@ -83,6 +83,9 @@ void Audio::Initialize(){ bgm.SetFadeTime(defaultFadeTime); } + if(data.HasProperty("Loop Repeat Start Point")){ + bgm.SetLoopStartTime(data["Loop Repeat Start Point"].GetReal()); + } if(data.HasProperty("Events")){ for(auto&eventName:Self().events){ @@ -175,6 +178,7 @@ void Audio::BGM::Load(){ } Self().currentBGM=songFileName; Self().currentLoopIndex=0; + Self().lastTimestamp=0.f; 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{ @@ -323,26 +327,38 @@ void Audio::PlayBGM(const std::string_view sound,const bool loop){ } void Audio::Update(){ - if(Self().fadeToTargetVolumeTime==0.f&&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().BGMFullyLoaded()&&Self().BGMIsPlaying()){ + Audio::BGM&track=Self().bgm[Self().GetTrackName()]; + float currentTimestamp{Engine().GetCursorMilliseconds(track.GetChannelIDs()[0])/1000.f}; + if(Self().lastTimestamp>currentTimestamp){ + for(int trackID:track.GetChannelIDs()){ + Engine().Seek(trackID,unsigned long long(track.GetLoopStartTime())*1000); } + currentTimestamp=Engine().GetCursorMilliseconds(track.GetChannelIDs()[0])/1000.f; //Update to new timestamp now that it's been shifted over. + } + Self().lastTimestamp=currentTimestamp; + }else{ + if(Self().fadeToTargetVolumeTime==0.f&&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. + } - //Start playing the tracks. - Audio::BGM&track=Self().bgm[Self().GetTrackName()]; - for(int trackID:track.GetChannelIDs()){ - Engine().Play(trackID,true); + //Start playing the tracks and setup a callback to repeat at looped time. + Audio::BGM&track=Self().bgm[Self().GetTrackName()]; + for(int trackID:track.GetChannelIDs()){ + Engine().Play(trackID,true); + } } } - } - if(Self().fadeToTargetVolumeTime>0.f){ - Self().fadeToTargetVolumeTime=std::max(0.f,Self().fadeToTargetVolumeTime-game->GetElapsedTime()); - for(int counter=0;float&vol:Self().prevVolumes){ - const BGM¤tBgm=Self().bgm[Self().currentBGM]; - Engine().SetVolume(currentBgm.GetChannelIDs()[counter],util::lerp(Self().GetCalculatedBGMVolume(vol),Self().GetCalculatedBGMVolume(Self().targetVolumes[counter]),1-(Self().fadeToTargetVolumeTime/currentBgm.GetFadeTime()))); - counter++; + if(Self().fadeToTargetVolumeTime>0.f){ + Self().fadeToTargetVolumeTime=std::max(0.f,Self().fadeToTargetVolumeTime-game->GetElapsedTime()); + for(int counter=0;float&vol:Self().prevVolumes){ + const BGM¤tBgm=Self().bgm[Self().currentBGM]; + Engine().SetVolume(currentBgm.GetChannelIDs()[counter],util::lerp(Self().GetCalculatedBGMVolume(vol),Self().GetCalculatedBGMVolume(Self().targetVolumes[counter]),1-(Self().fadeToTargetVolumeTime/currentBgm.GetFadeTime()))); + counter++; + } } } } @@ -355,6 +371,10 @@ const float&Audio::BGM::GetFadeTime()const{ return fadeTime; } +const float&Audio::BGM::GetLoopStartTime()const{ + return loopStartTime; +} + void Audio::SetBGMVolume(float vol){ bgmVol=vol; UpdateBGMVolume(); @@ -402,4 +422,8 @@ float Audio::GetMuteMult(){ int Audio::GetPrepareBGMLoopIterations(std::string_view sound){ BGM&newBgm=Self().bgm[std::string(sound)]; return newBgm.GetChannels().size()*2+2; //The channels list gets populated by calling newBgm.Load(), which then provides the list of channels that need to be loaded and played. This is why we multiply by 2. Each of the loading phases also consist of an initialization phase, so we add 2 as well. +} + +void Audio::BGM::SetLoopStartTime(const float loopStartTime){ + this->loopStartTime=loopStartTime; } \ No newline at end of file diff --git a/Adventures in Lestoria/Audio.h b/Adventures in Lestoria/Audio.h index 578db573..2e0b9155 100644 --- a/Adventures in Lestoria/Audio.h +++ b/Adventures in Lestoria/Audio.h @@ -118,12 +118,15 @@ private: const ChannelID&GetChannelID(const int index); const ChannelIDList&GetChannelIDs()const; const float&GetFadeTime()const; + const float&GetLoopStartTime()const; + void SetLoopStartTime(const float loopStartTime); private: std::string songName; //Name of the track. std::string songFileName; //Name of the key in bgm. ChannelIDList channels; std::vectorchannelNames; EventData eventVolumes; + float loopStartTime{0.f}; float fadeTime="BGM.Default Fade Time"_F; void Unload(); }; @@ -141,6 +144,7 @@ private: float playBGMWaitTime=0.0f; BGMPlayParams playParams; static bool muted; + float lastTimestamp{0.f}; }; std::string operator""_SFX(const char*key,size_t length); \ No newline at end of file diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index 9a80e0ee..af96362a 100644 --- a/Adventures in Lestoria/Version.h +++ b/Adventures in Lestoria/Version.h @@ -39,7 +39,7 @@ All rights reserved. #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_PATCH 3 -#define VERSION_BUILD 10918 +#define VERSION_BUILD 10936 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Adventures in Lestoria/assets/config/audio/bgm.txt b/Adventures in Lestoria/assets/config/audio/bgm.txt index e706fd1b..6ec2d2fa 100644 --- a/Adventures in Lestoria/assets/config/audio/bgm.txt +++ b/Adventures in Lestoria/assets/config/audio/bgm.txt @@ -12,6 +12,8 @@ BGM # Transition time between one phase to the next. Fade Time = 2.0 + Loop Repeat Start Point = 0.0s + Events { Default Volume = 70% @@ -28,6 +30,8 @@ BGM # Transition time between one phase to the next. Fade Time = 2.0 + Loop Repeat Start Point = 0.0s + Events { Default Volume = 70% @@ -44,6 +48,8 @@ BGM # Transition time between one phase to the next. Fade Time = 2.0 + Loop Repeat Start Point = 0.0s + Events { Default Volume = 70% @@ -65,6 +71,8 @@ BGM # Transition time between one phase to the next. Fade Time = 2.0 + Loop Repeat Start Point = 0.0s + Events { Default Volume = 0%,0%,0%,0%,50%,0% @@ -91,6 +99,8 @@ BGM # Transition time between one phase to the next. Fade Time = 2.0 + Loop Repeat Start Point = 0.0s + Events { Default Volume = 0%,60%,0%,0%,0%,0%,0%,0%,60%,60% @@ -112,6 +122,8 @@ BGM # Transition time between one phase to the next. Fade Time = 2.0 + Loop Repeat Start Point = 0.0s + Events { Default Volume = 20%,50%,20%,70% @@ -128,6 +140,8 @@ BGM # Transition time between one phase to the next. Fade Time = 2.0 + Loop Repeat Start Point = 0.0s + Events { Default Volume = 70% diff --git a/Adventures in Lestoria/olcPGEX_MiniAudio.h b/Adventures in Lestoria/olcPGEX_MiniAudio.h index 8891c35d..44608b93 100644 --- a/Adventures in Lestoria/olcPGEX_MiniAudio.h +++ b/Adventures in Lestoria/olcPGEX_MiniAudio.h @@ -432,9 +432,9 @@ namespace olc { unsigned long long cursor; ma_sound_get_cursor_in_pcm_frames(vecSounds.at(id), &cursor); - + + cursor *= 1000; cursor /= sampleRate; - cursor /= 1000; return cursor; } diff --git a/x64/Release/Adventures in Lestoria.exe b/x64/Release/Adventures in Lestoria.exe index 26e8e5c3..a41a8f91 100644 Binary files a/x64/Release/Adventures in Lestoria.exe and b/x64/Release/Adventures in Lestoria.exe differ