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

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

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

@ -42,20 +42,27 @@ All rights reserved.
INCLUDE_game
INCLUDE_DATA
float Audio::defaultFadeTime;
void Audio::Initialize(){
Audio&instance=game->audioEngine;
Self().events.insert("Default Volume");
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"]){
auto&data=DATA["BGM"][songFileName];
if(songFileName!="Default Fade Time"){
int channelCounter=0;
BGM&bgm=instance.bgm[songName];
BGM&bgm=Self().bgm[songFileName];
bgm.SetFileName(songFileName);
bgm.SetName(data["Track Name"].GetString());
while(data.HasProperty(std::format("channel[{}]",channelCounter))){
bgm.AddChannel(data[std::format("channel[{}]",channelCounter)].GetString());
std::string channelName=data[std::format("channel[{}]",channelCounter)].GetString();
if(!std::filesystem::exists("bgm_directory"_S+channelName))ERR(std::format("WARNING! Could not load file {} for track {}",channelName,songFileName));
bgm.AddChannel(channelName);
channelCounter++;
}
@ -64,21 +71,31 @@ void Audio::Initialize(){
VolumeList volumes;
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);
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"]){
for(auto&[eventName,size]:DATA["Events"]){
auto&eventData=data["Events"][eventName];
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<data.GetValueCount();i++){
volumes.push_back(data.GetInt(i));
for(int i=0;i<eventData.GetValueCount();i++){
volumes.push_back(eventData.GetInt(i)/100.f);
}
bgm.AddEventVolumes(eventName,volumes);
}
}
}else{
defaultFadeTime=data.GetReal();
}
}
}
@ -88,11 +105,69 @@ MiniAudio&Audio::Engine(){
void Audio::Play(const std::string_view sound){
Engine().Play(std::string(sound));
};
void Audio::PlayBGM(const std::string_view sound,const bool loop=true){
if(Engine().LoadS)
Engine().Play(std::string(sound));
void Audio::PlayBGM(const std::string_view sound,const bool loop){
BGM&track=Self().bgm[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){
this->fadeTime=fadeTime;
}
@ -112,6 +187,11 @@ const SongName&Audio::BGM::GetName()const{
void Audio::BGM::SetName(std::string_view name){
songName=name;
}
void Audio::BGM::SetFileName(std::string_view name){
songFileName=name;
}
void Audio::BGM::AddChannel(const ChannelName&name){
channelNames.push_back(name);
}
@ -125,9 +205,27 @@ void Audio::EventData::AddEventInfo(const Event&eventName,const VolumeList&volum
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){
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
#include "olcPGEX_MiniAudio.h"
#include "config.h"
#include <set>
using SongName=std::string;
using Event=std::string;
using ChannelName=std::string;
using ChannelIDList=std::vector<int>;
using VolumeList=std::vector<int>;
using ChannelID=int;
using ChannelIDList=std::vector<ChannelID>;
using Volume=float;
using VolumeList=std::vector<Volume>;
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{
std::map<Event,VolumeList>eventInfo;
public:
void AddEventInfo(const Event&eventName,const VolumeList&volumes);
const VolumeList&GetVolumes(const Event&event)const;
private:
std::map<Event,VolumeList>eventInfo;
};
class BGM{
std::string songName;
ChannelIDList channels;
std::vector<ChannelName>channelNames;
EventData eventVolumes;
float fadeTime="BGM.Default Fade Time"_F;
public:
void Load();
void Unload();
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;
void SetName(std::string_view name);
void SetFileName(std::string_view name);
void AddChannel(const ChannelName&name);
void AddEventVolumes(const Event&eventName,const VolumeList&volumes);
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;
SongName currentBGM;
SongName currentBGM="";
std::map<SongName,BGM>bgm;
std::set<Event>events;
public:
static MiniAudio&Engine();
static void Initialize();
static void Play(const std::string_view sound);
static void PlayBGM(const std::string_view sound,const bool loop=true);
static float defaultFadeTime;
Event currentAudioEvent="Default Volume";
};
std::string operator""_SFX(const char*key,size_t length);
std::string operator""_BGM(const char*key,size_t length);

@ -121,7 +121,8 @@ void Merchant::Initialize(){
ERR("Could not find item "<<itemNumber<<" in Merchant "<<merchantCount<<" of Chapter "<<chapter<<"!");
}
itemNumber++;
}else{
}else
{
ERR("Unhandled key "<<std::quoted(key)<<" inside of Merchant "<<merchantCount<<" of Chapter "<<chapter<<"!");
}
}

@ -109,6 +109,24 @@ void State_OverworldMap::OnUserUpdate(AiL*game){
if(game->GetKey(K1).bPressed){
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
for(ConnectionPoint&cp:connections){

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

@ -29,4 +29,23 @@ BGM
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/
# Path to bgm configuration
bgm_config = bgm.txt
bgm_config = bgm/bgm.txt
# Path to bgm events configuration
event_config = events.txt
event_config = bgm/events.txt
# Path to character images
character_image_location = characters/

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

Loading…
Cancel
Save