Implement all audio events and loading/unloading functionality for multi-channel BGM support.

pull/28/head
sigonasr2 11 months ago
parent 72c8796dcb
commit 8afa9889af
  1. 7
      Adventures in Lestoria/AdventuresInLestoria.cpp
  2. 158
      Adventures in Lestoria/Audio.cpp
  3. 54
      Adventures in Lestoria/Audio.h
  4. 18
      Adventures in Lestoria/State_OverworldMap.cpp
  5. 2
      Adventures in Lestoria/Version.h
  6. 19
      Adventures in Lestoria/assets/config/bgm/bgm.txt
  7. 4
      Adventures in Lestoria/assets/config/configuration.txt
  8. BIN
      Adventures in Lestoria/assets/music/foresty0.mp3
  9. BIN
      Adventures in Lestoria/assets/music/foresty0_alt.mp3
  10. 4
      Adventures in Lestoria/olcUTIL_DataFile.h

@ -137,8 +137,9 @@ AiL::AiL()
std::string ITEM_STATS_CONFIG = CONFIG_PATH + "item_stats_config"_S; std::string ITEM_STATS_CONFIG = CONFIG_PATH + "item_stats_config"_S;
utils::datafile::Read(DATA,ITEM_STATS_CONFIG); utils::datafile::Read(DATA,ITEM_STATS_CONFIG);
for(auto&[key,value]:DATA.GetProperty("ItemConfiguration").GetKeys()){ auto keys=DATA.GetProperty("ItemConfiguration");
std::string config = DATA["ItemConfiguration"][key].GetString(); for(auto&[key,value]:keys){
std::string config=DATA["ItemConfiguration"][key].GetString();
utils::datafile::Read(DATA,CONFIG_PATH + "item_directory"_S + config); utils::datafile::Read(DATA,CONFIG_PATH + "item_directory"_S + config);
} }
@ -242,6 +243,8 @@ bool AiL::OnUserCreate(){
Stats::InitializeDamageReductionTable(); Stats::InitializeDamageReductionTable();
Audio::Initialize();
utils::datafile::INITIAL_SETUP_COMPLETE=true; utils::datafile::INITIAL_SETUP_COMPLETE=true;
ValidateGameStatus(); //Checks to make sure everything has been initialized properly. ValidateGameStatus(); //Checks to make sure everything has been initialized properly.

@ -42,42 +42,59 @@ All rights reserved.
INCLUDE_game INCLUDE_game
INCLUDE_DATA INCLUDE_DATA
float Audio::defaultFadeTime;
void Audio::Initialize(){ void Audio::Initialize(){
Audio&instance=game->audioEngine; Self().events.insert("Default Volume");
for(auto&[key,data]:DATA["Events"]){ for(auto&[key,data]:DATA["Events"]){
instance.events.insert(key); Self().events.insert(key);
} }
for(auto&[songName,data]:DATA["BGM"]){ for(auto&[songFileName,size]:DATA["BGM"]){
int channelCounter=0; auto&data=DATA["BGM"][songFileName];
if(songFileName!="Default Fade Time"){
int channelCounter=0;
BGM&bgm=instance.bgm[songName]; BGM&bgm=Self().bgm[songFileName];
bgm.SetName(data["Track Name"].GetString()); bgm.SetFileName(songFileName);
bgm.SetName(data["Track Name"].GetString());
while(data.HasProperty(std::format("channel[{}]",channelCounter))){ while(data.HasProperty(std::format("channel[{}]",channelCounter))){
bgm.AddChannel(data[std::format("channel[{}]",channelCounter)].GetString()); std::string channelName=data[std::format("channel[{}]",channelCounter)].GetString();
channelCounter++; if(!std::filesystem::exists("bgm_directory"_S+channelName))ERR(std::format("WARNING! Could not load file {} for track {}",channelName,songFileName));
} bgm.AddChannel(channelName);
channelCounter++;
}
if(!data.HasProperty("Default Volume"))ERR(std::format("WARNING! Track {} does not have a Default Volume parameter!",bgm.GetName())); if(!data.HasProperty("Default Volume"))ERR(std::format("WARNING! Track {} does not have a Default Volume parameter!",bgm.GetName()));
if(data["Default Volume"].GetValueCount()!=bgm.GetChannelCount())ERR(std::format("WARNING! Default Volume parameters do not match channel count. {} != {}",data["Default Volume"].GetValueCount(),bgm.GetChannelCount())); if(data["Default Volume"].GetValueCount()!=bgm.GetChannelCount())ERR(std::format("WARNING! Default Volume parameters do not match channel count. {} != {}",data["Default Volume"].GetValueCount(),bgm.GetChannelCount()));
VolumeList volumes; VolumeList volumes;
for(int i=0;i<data["Default Volume"].GetValueCount();i++){ for(int i=0;i<data["Default Volume"].GetValueCount();i++){
volumes.push_back(data["Default Volume"].GetInt(i)); volumes.push_back(data["Default Volume"].GetInt(i)/100.f);
} }
bgm.AddEventVolumes("Default Volume",volumes); bgm.AddEventVolumes("Default Volume",volumes);
if(data.HasProperty("Fade Time"))bgm.SetFadeTime(data["Fade Time"].GetReal()); if(data.HasProperty("Fade Time")){
bgm.SetFadeTime(data["Fade Time"].GetReal());
}else{
bgm.SetFadeTime(defaultFadeTime);
}
if(data.HasProperty("Events")){
for(auto&[eventName,data]:DATA["Events"]){ if(data.HasProperty("Events")){
VolumeList volumes; for(auto&[eventName,size]:DATA["Events"]){
for(int i=0;i<data.GetValueCount();i++){ auto&eventData=data["Events"][eventName];
volumes.push_back(data.GetInt(i)); if(eventData.GetValueCount()!=bgm.GetChannelCount())ERR(std::format("WARNING! {} parameters do not match channel count. {} != {}",eventName,eventData.GetValueCount(),bgm.GetChannelCount()));
VolumeList volumes;
for(int i=0;i<eventData.GetValueCount();i++){
volumes.push_back(eventData.GetInt(i)/100.f);
}
bgm.AddEventVolumes(eventName,volumes);
} }
bgm.AddEventVolumes(eventName,volumes);
} }
}else{
defaultFadeTime=data.GetReal();
} }
} }
} }
@ -88,11 +105,69 @@ MiniAudio&Audio::Engine(){
void Audio::Play(const std::string_view sound){ void Audio::Play(const std::string_view sound){
Engine().Play(std::string(sound)); Engine().Play(std::string(sound));
}; };
void Audio::PlayBGM(const std::string_view sound,const bool loop=true){ void Audio::PlayBGM(const std::string_view sound,const bool loop){
if(Engine().LoadS) BGM&track=Self().bgm[std::string(sound)];
Engine().Play(std::string(sound)); StopBGM(); //Stop any currently playing track.
track.Load();
for(int channelListIndex=0;int trackID:track.GetChannelIDs()){
Engine().SetVolume(trackID,track.GetVolume(Self().currentAudioEvent,channelListIndex));
Engine().Play(trackID,loop);
channelListIndex++;
}
}; };
void Audio::StopBGM(){
if(Self().BGMIsPlaying()){
BGM&currentTrack=Self().bgm[Self().currentBGM];
for(int trackID:currentTrack.GetChannelIDs()){
Engine().Stop(trackID);
}
}
}
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);
}
void Audio::BGM::Load(){
BGM&bgm=Self().bgm[Self().currentBGM];
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: {}",bgm.channels.size()));
for(const ChannelName&channel:newBgm.GetChannels()){
ChannelID soundID=Engine().LoadSound("bgm_directory"_S+channel);
newBgm.channels.push_back(soundID);
}
}
void Audio::BGM::Unload(){
BGM&bgm=Self().bgm[Self().currentBGM];
for(const ChannelID&id:channels){
Engine().UnloadSound(id);
}
channels.clear();
Self().currentBGM="";
}
const ChannelID&Audio::BGM::GetChannelID(const int index){
return channels[index];
}
const ChannelIDList&Audio::BGM::GetChannelIDs()const{
return channels;
}
const std::vector<ChannelName>&Audio::BGM::GetChannels()const{
return channelNames;
}
void Audio::BGM::SetFadeTime(const float fadeTime){ void Audio::BGM::SetFadeTime(const float fadeTime){
this->fadeTime=fadeTime; this->fadeTime=fadeTime;
} }
@ -112,6 +187,11 @@ const SongName&Audio::BGM::GetName()const{
void Audio::BGM::SetName(std::string_view name){ void Audio::BGM::SetName(std::string_view name){
songName=name; songName=name;
} }
void Audio::BGM::SetFileName(std::string_view name){
songFileName=name;
}
void Audio::BGM::AddChannel(const ChannelName&name){ void Audio::BGM::AddChannel(const ChannelName&name){
channelNames.push_back(name); channelNames.push_back(name);
} }
@ -125,9 +205,27 @@ void Audio::EventData::AddEventInfo(const Event&eventName,const VolumeList&volum
eventInfo[eventName]=volumes; eventInfo[eventName]=volumes;
} }
Audio&Audio::Self(){
return game->audioEngine;
}
const Event&Audio::GetAudioEvent(){
return Self().currentAudioEvent;
}
void Audio::SetAudioEvent(const Event&eventName){
if(Self().events.find(eventName)==Self().events.end())ERR(std::format("WARNING! cannot find event {}",eventName));
Self().currentAudioEvent=eventName;
if(Audio::BGMIsPlaying()){
BGM&currentBgm=Self().bgm[Self().currentBGM];
for(int currentTrackIndex=0;int trackID:currentBgm.GetChannelIDs()){
Engine().SetVolume(trackID,currentBgm.GetVolume(eventName,currentTrackIndex));
currentTrackIndex++;
}
}
}
std::string operator""_SFX(const char*key,size_t length){ std::string operator""_SFX(const char*key,size_t length){
return "sfx_directory"_S+std::string(key,length); return "sfx_directory"_S+std::string(key,length);
} }
std::string operator""_BGM(const char*key,size_t length){
return "bgm_directory"_S+std::string(key,length);
}

@ -38,46 +38,66 @@ All rights reserved.
#pragma once #pragma once
#include "olcPGEX_MiniAudio.h" #include "olcPGEX_MiniAudio.h"
#include "config.h" #include "config.h"
#include <set>
using SongName=std::string; using SongName=std::string;
using Event=std::string; using Event=std::string;
using ChannelName=std::string; using ChannelName=std::string;
using ChannelIDList=std::vector<int>; using ChannelID=int;
using VolumeList=std::vector<int>; using ChannelIDList=std::vector<ChannelID>;
using Volume=float;
using VolumeList=std::vector<Volume>;
class Audio{ class Audio{
public:
static Audio&Self();
static MiniAudio&Engine();
static void Initialize();
static void Play(const std::string_view sound);
//Play 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();
static void SetAudioEvent(const Event&eventName);
static const bool BGMIsPlaying();
private:
class EventData{ class EventData{
std::map<Event,VolumeList>eventInfo;
public: public:
void AddEventInfo(const Event&eventName,const VolumeList&volumes); void AddEventInfo(const Event&eventName,const VolumeList&volumes);
const VolumeList&GetVolumes(const Event&event)const; const VolumeList&GetVolumes(const Event&event)const;
private:
std::map<Event,VolumeList>eventInfo;
}; };
class BGM{ class BGM{
std::string songName; public:
ChannelIDList channels;
std::vector<ChannelName>channelNames;
EventData eventVolumes;
float fadeTime="BGM.Default Fade Time"_F;
public:
void Load(); void Load();
void Unload();
const size_t GetChannelCount()const; const size_t GetChannelCount()const;
const std::vector<ChannelName>&GetChannels()const;
const SongName&GetName()const; const SongName&GetName()const;
const Volume&GetVolume(const Event&eventName,const ChannelID&id)const;
void SetName(std::string_view name); void SetName(std::string_view name);
void SetFileName(std::string_view name);
void AddChannel(const ChannelName&name); void AddChannel(const ChannelName&name);
void AddEventVolumes(const Event&eventName,const VolumeList&volumes); void AddEventVolumes(const Event&eventName,const VolumeList&volumes);
void SetFadeTime(const float fadeTime); void SetFadeTime(const float fadeTime);
const ChannelID&GetChannelID(const int index);
const ChannelIDList&GetChannelIDs()const;
private:
std::string songName; //Name of the track.
std::string songFileName; //Name of the key in bgm.
ChannelIDList channels;
std::vector<ChannelName>channelNames;
EventData eventVolumes;
float fadeTime="BGM.Default Fade Time"_F;
void Unload();
}; };
private:
MiniAudio audioEngine; MiniAudio audioEngine;
SongName currentBGM; SongName currentBGM="";
std::map<SongName,BGM>bgm; std::map<SongName,BGM>bgm;
std::set<Event>events; std::set<Event>events;
public: static float defaultFadeTime;
static MiniAudio&Engine(); Event currentAudioEvent="Default Volume";
static void Initialize();
static void Play(const std::string_view sound);
static void PlayBGM(const std::string_view sound,const bool loop=true);
}; };
std::string operator""_SFX(const char*key,size_t length); std::string operator""_SFX(const char*key,size_t length);
std::string operator""_BGM(const char*key,size_t length);

@ -109,6 +109,24 @@ void State_OverworldMap::OnUserUpdate(AiL*game){
if(game->GetKey(K1).bPressed){ if(game->GetKey(K1).bPressed){
Audio::Play("sfx100v2_loop_water_01.mp3"_SFX); Audio::Play("sfx100v2_loop_water_01.mp3"_SFX);
} }
if(game->GetKey(F1).bPressed){
Audio::PlayBGM("foresty1_1");
}else
if(game->GetKey(F2).bPressed){
Audio::PlayBGM("foresty0");
}
if(game->GetKey(K2).bPressed){
Audio::SetAudioEvent("Default Volume");
}
if(game->GetKey(K3).bPressed){
Audio::SetAudioEvent("LowHealth");
}
if(game->GetKey(K4).bPressed){
Audio::SetAudioEvent("InCombat");
}
if(game->GetKey(K5).bPressed){
Audio::SetAudioEvent("Underwater");
}
#pragma region Handle Connection Point Clicking and Movement #pragma region Handle Connection Point Clicking and Movement
for(ConnectionPoint&cp:connections){ for(ConnectionPoint&cp:connections){

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 2 #define VERSION_MINOR 2
#define VERSION_PATCH 1 #define VERSION_PATCH 1
#define VERSION_BUILD 5353 #define VERSION_BUILD 5379
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -29,4 +29,23 @@ BGM
Underwater = 0%,0%,100%,100% Underwater = 0%,0%,100%,100%
} }
} }
foresty0
{
Track Name = Foresty Preview
channel[0]=foresty0.mp3
channel[1]=foresty0_alt.mp3
Default Volume = 70%,0%
# Transition time between one phase to the next.
Fade Time = 2.0
Events
{
LowHealth = 50%,20%
InCombat = 100%,0%
Underwater = 0%,100%
}
}
} }

@ -66,10 +66,10 @@ sfx_directory = assets/sounds/
bgm_directory = assets/music/ bgm_directory = assets/music/
# Path to bgm configuration # Path to bgm configuration
bgm_config = bgm.txt bgm_config = bgm/bgm.txt
# Path to bgm events configuration # Path to bgm events configuration
event_config = events.txt event_config = bgm/events.txt
# Path to character images # Path to character images
character_image_location = characters/ character_image_location = characters/

@ -488,10 +488,10 @@ namespace olc::utils
} }
inline auto begin(){ inline auto begin(){
return GetOrderedKeys().begin(); return GetKeys().begin();
} }
inline auto end(){ inline auto end(){
return GetOrderedKeys().end(); return GetKeys().end();
} }
private: private:

Loading…
Cancel
Save