Merge pull request 'audio-buffer-through-resource-pack' (#65) from audio-buffer-through-resource-pack into master

This PR adds the ability for BGM tracks to be encrypted away inside the PGE resource pack system such that it will be more difficult for users to extract the songs from the game.

Because of this, we load the tracks in memory now reading directly from a buffer. (Luckily miniaudio makes this really easy to tack onto the existing pipeline)

Another additional change had to be made with manual loading of sounds. If we want to store a sound ID and track it ourselves, we are now required to specify it's a sound effect to prevent it from getting read as a resource pack item.

Reviewed-on: #65
demo
sigonasr2 2 months ago
commit ce1caabc90
  1. 7
      Adventures in Lestoria/AdventuresInLestoria.cpp
  2. 1
      Adventures in Lestoria/AdventuresInLestoria.h
  3. 7
      Adventures in Lestoria/Audio.cpp
  4. 2
      Adventures in Lestoria/Audio.h
  5. 2
      Adventures in Lestoria/EnvironmentalAudio.cpp
  6. 2
      Adventures in Lestoria/Player.cpp
  7. 2
      Adventures in Lestoria/SoundEffect.cpp
  8. 2
      Adventures in Lestoria/State_LevelComplete.cpp
  9. 5
      Adventures in Lestoria/TODO.txt
  10. 2
      Adventures in Lestoria/Version.h
  11. BIN
      Adventures in Lestoria/assets/gamepack.pak
  12. 48
      Adventures in Lestoria/olcPGEX_MiniAudio.h
  13. 2
      Adventures in Lestoria/olcPixelGameEngine.h
  14. 6
      Adventures in Lestoria/pixelGameEngine.cpp
  15. BIN
      x64/Release/Adventures in Lestoria.exe

@ -4447,11 +4447,8 @@ void AiL::GlobalGameUpdates(){
Audio::Engine().SetVolume(GetPlayer()->cooldownSoundInstance,Audio::GetCalculatedSFXVolume("Audio.Casting Sound Volume"_F/100.f));
}
if(!GamePaused()){
GameState::STATE->OnUserUpdate(this);
}else{
ClearTimedOutGarbage();
}
if(!GamePaused())GameState::STATE->OnUserUpdate(this);
else ClearTimedOutGarbage();
}

@ -95,6 +95,7 @@ class AiL : public olc::PixelGameEngine
friend class sig::Animation;
friend class Audio;
friend class Minimap;
friend class MiniAudio;
std::unique_ptr<Player>player;
SplashScreen splash;
public:

@ -71,6 +71,9 @@ void Audio::Initialize(){
while(data.HasProperty(std::format("channel[{}]",channelCounter))){
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));
if(!game->gamepack.Loaded()&&"GENERATE_GAMEPACK"_B){
game->gamepack.AddFile("bgm_directory"_S+channelName);
}
bgm.AddChannel(channelName);
channelCounter++;
}
@ -121,8 +124,8 @@ MiniAudio&Audio::Engine(){
void Audio::Play(const std::string_view sound){
Engine().Play(std::string(sound));
};
const size_t Audio::LoadAndPlay(const std::string_view sound,const bool loop){
size_t soundID=Engine().LoadSound(std::string(sound));
const size_t Audio::LoadAndPlaySFX(const std::string_view sound,const bool loop){
size_t soundID=Engine().LoadSound(std::string(sound),MiniAudio::SFX);
Engine().Play(soundID,loop);
return soundID;
};

@ -59,7 +59,7 @@ public:
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);
static const size_t LoadAndPlaySFX(const std::string_view sound,const bool loop=true);
//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.

@ -67,7 +67,7 @@ void EnvironmentalAudio::SetAudioName(const std::string_view audioName){
}
void EnvironmentalAudio::Activate(){
if(activated)return;
soundInstance=Audio::LoadAndPlay(operator""_SFX(SOUND_DATA[audioName].file.c_str(),SOUND_DATA[audioName].file.length()),true);
soundInstance=Audio::LoadAndPlaySFX(operator""_SFX(SOUND_DATA[audioName].file.c_str(),SOUND_DATA[audioName].file.length()),true);
activated=true;
}
void EnvironmentalAudio::Deactivate(){

@ -115,7 +115,7 @@ void Player::Initialize(){
SetBaseStat("HP Recovery %",0);
SetBaseStat("Damage Reduction",0);
SetBaseStat("Attack Spd",0);
cooldownSoundInstance=Audio::Engine().LoadSound("spell_cast.ogg"_SFX);
cooldownSoundInstance=Audio::Engine().LoadSound("spell_cast.ogg"_SFX,MiniAudio::SFX);
afterImage.Create(24,24);
for(Pixel&p:afterImage.Sprite()->pColData){
p.a=0;

@ -115,7 +115,7 @@ void SoundEffect::PlaySFX(const std::string&eventName,const vf2d&pos){
size_t SoundEffect::PlayLoopingSFX(const std::string&eventName,const vf2d&pos){
if(game->TestingModeEnabled()||eventName.length()==0)return 0U;
const SoundEffect&sfx=GetRandomSFXFromFile(eventName);
const size_t id=Audio::Engine().LoadSound(operator""_SFX(sfx.filename.c_str(),sfx.filename.length()));
const size_t id=Audio::Engine().LoadSound(operator""_SFX(sfx.filename.c_str(),sfx.filename.length()),MiniAudio::SFX);
RepeatingSoundEffect::playingSoundEffects.insert(id);
Audio::Engine().Play(id,true);
return id;

@ -51,7 +51,7 @@ INCLUDE_game
void State_LevelComplete::OnStateChange(GameState*prevState){
if(xpGainSound==std::numeric_limits<size_t>::max()){
xpGainSound=Audio::LoadAndPlay("xpgain.ogg"_SFX,true);
xpGainSound=Audio::LoadAndPlaySFX("xpgain.ogg"_SFX,true);
Audio::Engine().SetVolume(xpGainSound,0.f);
}
if(Menu::IsMenuOpen()){

@ -17,7 +17,10 @@ New Monster Sound Effects
Add a Helper Function: Change proximity knockback checks regardless of player/monster friendliness to be a function call instead.
Add rectangular hitbox posssibility to the game for monsters. (specifically for use with pillars)
Add rectangular hitbox possibility to the game for monsters. (specifically for use with pillars)
Fanfare -> Post boss song
DEMO
====

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1
#define VERSION_MINOR 2
#define VERSION_PATCH 5
#define VERSION_BUILD 11508
#define VERSION_BUILD 11541
#define stringify(a) stringify_(a)
#define stringify_(a) #a

@ -81,8 +81,13 @@ namespace olc
// set whether audio will continue playing when the app has lost focus
void SetBackgroundPlay(bool state);
public: // LOADING ROUTINES
const size_t LoadSound(const std::string& path);
public: // LOADING ROUTINES
enum SoundEffectFlag{
SFX,
BGM,
};
const size_t LoadSound(const std::string& path,const SoundEffectFlag soundType=BGM); //Setting sound effect to true avoids loading it from a resource pack.
const size_t LoadResource(const std::string& path);
void UnloadSound(const int id);
public: // PLAYBACK CONTROLS
@ -153,6 +158,15 @@ namespace olc
// this is where the sounds are kept
std::vector<ma_sound*> vecSounds;
std::vector<ma_sound*> vecOneOffSounds;
struct ResourceData{
ma_engine*engine;
ResourceBuffer data;
std::string pathName;
~ResourceData(){
if(ma_resource_manager_unregister_data(ma_engine_get_resource_manager(engine),pathName.data())!=MA_SUCCESS)ERR(std::format("WARNING! Could not clear resources for {}!",pathName));
};
};
std::unordered_map<size_t,ResourceData>vecResourceData;
};
/**
@ -200,6 +214,10 @@ namespace olc
#ifdef OLC_PGEX_MINIAUDIO
#undef OLC_PGEX_MINIAUDIO
#include "AdventuresInLestoria.h"
INCLUDE_game
namespace olc
{
bool MiniAudio::backgroundPlay = false;
@ -290,28 +308,35 @@ namespace olc
MiniAudio::backgroundPlay = state;
}
const size_t MiniAudio::LoadSound(const std::string& path)
const size_t MiniAudio::LoadSound(const std::string& path,const SoundEffectFlag soundType)
{
// create the sound
ma_sound* sound = new ma_sound();
// assume no empty slots...
size_t id = vecSounds.size();
// load it from the file and decode it
if(ma_sound_init_from_file(&engine, path.c_str(), MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_ASYNC, NULL, NULL, sound) != MA_SUCCESS)
throw MiniAudioSoundException();
bool foundSound{false};
// attempt to re-use an empty slot
for(int i = 0; i < vecSounds.size(); i++)
{
if(vecSounds.at(i) == nullptr)
{
vecSounds.at(i) = sound;
return i;
id=i;
foundSound=true;
break;
}
}
if(!foundSound)vecSounds.emplace_back(sound);
// no empty slots, make more room!
const size_t id = vecSounds.size();
vecSounds.push_back(sound);
if(soundType==BGM){
vecResourceData[id]={&engine,game->gamepack.GetFileBuffer(path),path};
if(ma_resource_manager_register_encoded_data(ma_engine_get_resource_manager(&engine),path.data(),vecResourceData[id].data.vMemory.data(),vecResourceData[id].data.vMemory.size())!=MA_SUCCESS)ERR(std::format("WARNING! Could not load resources for {}!",path));
}
if(ma_sound_init_from_file(&engine, path.c_str(), MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_ASYNC, NULL, NULL, sound) != MA_SUCCESS)
throw MiniAudioSoundException();
return id;
}
@ -321,6 +346,7 @@ namespace olc
ma_sound_uninit(vecSounds.at(id));
delete vecSounds.at(id);
vecSounds.at(id) = nullptr;
if(vecResourceData.count(id))vecResourceData.erase(id);
}
void MiniAudio::Play(const int id, const bool loop)

@ -713,6 +713,7 @@ namespace olc
// O------------------------------------------------------------------------------O
struct ResourceBuffer : public std::streambuf
{
ResourceBuffer();
ResourceBuffer(std::ifstream& ifs, uint32_t offset, uint32_t size);
std::vector<char> vMemory;
};
@ -1794,6 +1795,7 @@ namespace olc
//=============================================================
// Resource Packs - Allows you to store files in one large
// scrambled file - Thanks MaGetzUb for debugging a null char in std::stringstream bug
ResourceBuffer::ResourceBuffer(){}
ResourceBuffer::ResourceBuffer(std::ifstream& ifs, uint32_t offset, uint32_t size)
{
vMemory.resize(size);

@ -51,9 +51,9 @@ All rights reserved.
#include "TMXParser.h"
#define TSX_PARSER_SETUP
#include "TSXParser.h"
#define OLC_PGEX_MINIAUDIO
#include "olcPGEX_MiniAudio.h"
#define OLC_PGEX_SPLASHSCREEN
#include "olcPGEX_SplashScreen.h"
#define OLC_PGE_GAMEPAD
#include "olcPGEX_Gamepad.h"
#include "olcPGEX_Gamepad.h"
#define OLC_PGEX_MINIAUDIO
#include "olcPGEX_MiniAudio.h"
Loading…
Cancel
Save