Skip to content

Implement some sound priorities #1759

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 110 additions & 44 deletions src/engine/audio/Audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,70 @@ namespace Audio {
// in a frame, it means it sould be destroyed.
struct entityLoop_t {
bool addedThisFrame;
bool persistent;
std::shared_ptr<LoopingSound> sound;
sfxHandle_t newSfx;
sfxHandle_t oldSfx;
};
static entityLoop_t entityLoops[MAX_GENTITIES];

struct EntityMultiLoop {
entityLoop_t loops[MAX_ENTITY_SOUNDS];

entityLoop_t& FindSlot( const sfxHandle_t sfx ) {
uint32_t bestSlot = 0;
float minGain = FLT_MAX;

for ( entityLoop_t& loop : loops ) {
if ( sfx == loop.oldSfx ) {
return loop;
}

if ( !loop.sound ) {
return loop;
}

if ( loop.sound->currentGain < minGain ) {
bestSlot = &loop - loops;
minGain = loop.sound->currentGain;
}
}

return loops[bestSlot];
}

void StopAll() {
for ( entityLoop_t& loop : loops ) {
if ( loop.sound ) {
loop.sound->Stop();
}

loop = { false, false, nullptr, -1, -1 };
}
}

void ResetAll() {
for ( entityLoop_t& loop : loops ) {
loop = { false, false, nullptr, -1, -1 };
}
}

void ClearLoopingSounds() {
for ( entityLoop_t& loop : loops ) {
if ( loop.sound ) {
loop.addedThisFrame = false;
}
}
}
};

static EntityMultiLoop entityLoops[MAX_GENTITIES];

static std::shared_ptr<StreamingSound> streams[N_STREAMS];

static bool initialized = false;

int playerClientNum;

static AL::Device* device;
static AL::Context* context;

Expand Down Expand Up @@ -147,8 +201,8 @@ namespace Audio {

UpdateListenerGain();

for (auto &loop : entityLoops) {
loop = {false, nullptr, -1, -1};
for ( EntityMultiLoop& loop : entityLoops ) {
loop.ResetAll();
}

return true;
Expand All @@ -160,11 +214,8 @@ namespace Audio {
}

// Shuts down the wrapper
for (auto &loop : entityLoops) {
if (loop.sound) {
loop.sound->Stop();
}
loop = {false, nullptr, -1, -1};
for ( EntityMultiLoop& loop : entityLoops ) {
loop.StopAll();
}

StopMusic();
Expand Down Expand Up @@ -193,22 +244,29 @@ namespace Audio {
return;
}

for (int i = 0; i < MAX_GENTITIES; i++) {
auto& loop = entityLoops[i];
if (loop.sound and not loop.addedThisFrame) {
// The loop wasn't added this frame, that means it has to be removed.
loop.sound->FadeOutAndDie();
loop = {false, nullptr, -1, -1};

} else if (loop.oldSfx != loop.newSfx) {
// The last sfx added in the frame is not the current one being played
// To mimic the previous sound system's behavior we sart playing the new one.
loop.sound->FadeOutAndDie();

int newSfx = loop.newSfx;
loop = {false, nullptr, -1, -1};

AddEntityLoopingSound(i, newSfx);
for ( uint32_t i = 0; i < MAX_GENTITIES; i++ ) {
EntityMultiLoop& multiLoop = entityLoops[i];

for ( entityLoop_t& loop : multiLoop.loops ) {
if ( loop.sound and not loop.addedThisFrame ) {
if ( loop.persistent ) {
loop.sound->soundGain = 0;
} else {
// The loop wasn't added this frame, that means it has to be removed.
loop.sound->FadeOutAndDie();
loop = { false, false, nullptr, -1, -1 };
}
} else if ( loop.oldSfx != loop.newSfx ) {
// The last sfx added in the frame is not the current one being played
// To mimic the previous sound system's behavior we sart playing the new one.
loop.sound->FadeOutAndDie();

int newSfx = loop.newSfx;
bool persistent = loop.persistent;
loop = { false, false, nullptr, -1, -1 };

AddEntityLoopingSound( i, newSfx, persistent );
}
}
}

Expand All @@ -219,26 +277,30 @@ namespace Audio {
UpdateEmitters();
UpdateSounds();

for (auto &loop : entityLoops) {
loop.addedThisFrame = false;
// if we are the unique owner of a loop pointer, then it means it was stopped, free it.
if (loop.sound.use_count() == 1) {
loop = {false, nullptr, -1, -1};
for ( EntityMultiLoop& multiLoop : entityLoops ) {
for ( entityLoop_t& loop : multiLoop.loops ) {
loop.addedThisFrame = false;
// if we are the unique owner of a loop pointer, then it means it was stopped, free it.
if ( loop.sound.use_count() == 1 ) {
loop = { false, false, nullptr, -1, -1 };
}
}
}

for (auto &stream : streams) {
for ( std::shared_ptr<StreamingSound> &stream : streams ) {
if (stream and stream.use_count() == 1) {
stream = nullptr;
}
}
}

void BeginRegistration() {
void BeginRegistration( const int playerNum ) {
if (not initialized) {
return;
}

playerClientNum = playerNum;

BeginSampleRegistration();
}

Expand All @@ -259,6 +321,10 @@ namespace Audio {
EndSampleRegistration();
}

static int GetSoundPriorityForEntity( const int entityNum ) {
return entityNum < MAX_CLIENTS ? CLIENT : ANY;
}

void StartSound(int entityNum, Vec3 origin, sfxHandle_t sfx) {
if (not initialized or not Sample::IsValidHandle(sfx)) {
return;
Expand All @@ -277,31 +343,33 @@ namespace Audio {
return;
}

AddSound(emitter, std::make_shared<OneShotSound>(Sample::FromHandle(sfx)), 1);
AddSound( emitter, std::make_shared<OneShotSound>( Sample::FromHandle( sfx ) ), GetSoundPriorityForEntity( entityNum ) );
}

void StartLocalSound(sfxHandle_t sfx) {
if (not initialized or not Sample::IsValidHandle(sfx)) {
return;
}

AddSound(GetLocalEmitter(), std::make_shared<OneShotSound>(Sample::FromHandle(sfx)), 1);
AddSound( GetLocalEmitter(), std::make_shared<OneShotSound>( Sample::FromHandle( sfx ) ), ANY );
}

void AddEntityLoopingSound(int entityNum, sfxHandle_t sfx) {
void AddEntityLoopingSound(int entityNum, sfxHandle_t sfx, bool persistent) {
if (not initialized or not Sample::IsValidHandle(sfx) or not IsValidEntity(entityNum)) {
return;
}

entityLoop_t& loop = entityLoops[entityNum];
entityLoop_t& loop = entityLoops[entityNum].FindSlot( sfx );

// If we have no sound we can play the loop directly
if (not loop.sound) {
loop.sound = std::make_shared<LoopingSound>(Sample::FromHandle(sfx));
loop.oldSfx = sfx;
AddSound(GetEmitterForEntity(entityNum), loop.sound, 1);
AddSound( GetEmitterForEntity( entityNum ), loop.sound, GetSoundPriorityForEntity( entityNum ) );
}

loop.addedThisFrame = true;
loop.persistent = persistent;

// We remember what is the last sfx asked because cgame expects the sfx added last in the frame to be played
loop.newSfx = sfx;
Expand All @@ -322,9 +390,7 @@ namespace Audio {
return;
}

if (entityLoops[entityNum].sound) {
entityLoops[entityNum].addedThisFrame = false;
}
entityLoops[entityNum].ClearLoopingSounds();
}

void StartMusic(Str::StringRef leadingSound, Str::StringRef loopSound) {
Expand All @@ -343,8 +409,8 @@ namespace Audio {

StopMusic();
music = std::make_shared<LoopingSound>(loopingSample, leadingSample);
music->SetVolumeModifier(musicVolume);
AddSound(GetLocalEmitter(), music, 1);
music->volumeModifier = &musicVolume;
AddSound( GetLocalEmitter(), music, ANY );
}

void StopMusic() {
Expand Down Expand Up @@ -375,13 +441,13 @@ namespace Audio {
if (not streams[streamNum]) {
streams[streamNum] = std::make_shared<StreamingSound>();
if (IsValidEntity(entityNum)) {
AddSound(GetEmitterForEntity(entityNum), streams[streamNum], 1);
AddSound( GetEmitterForEntity( entityNum ), streams[streamNum], GetSoundPriorityForEntity( entityNum ) );
} else {
AddSound(GetLocalEmitter(), streams[streamNum], 1);
AddSound( GetLocalEmitter(), streams[streamNum], ANY );
}
}

streams[streamNum]->SetGain(volume);
streams[streamNum]->soundGain = volume;

AudioData audioData(rate, width, channels, (width * numSamples * channels),
reinterpret_cast<const char*>(data));
Expand Down
4 changes: 2 additions & 2 deletions src/engine/audio/Audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ namespace Audio {
void Shutdown();
void Update();

void BeginRegistration();
void BeginRegistration( const int playerNum );
sfxHandle_t RegisterSFX(Str::StringRef filename);
void EndRegistration();

void StartSound(int entityNum, Vec3 origin, sfxHandle_t sfx);
void StartLocalSound(int entityNum);

void AddEntityLoopingSound(int entityNum, sfxHandle_t sfx);
void AddEntityLoopingSound(int entityNum, sfxHandle_t sfx, bool persistent);
void ClearAllLoopingSounds();
void ClearLoopingSoundsForEntity(int entityNum);

Expand Down
17 changes: 17 additions & 0 deletions src/engine/audio/AudioPrivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,23 @@ namespace Audio {
// There is only a small number of reverb slots because by default we can create only 4 AuxEffects
CONSTEXPR int N_REVERB_SLOTS = 3;

constexpr uint32_t MAX_ENTITY_SOUNDS = 4;

extern int playerClientNum;

struct entityData_t {
Vec3 position;
Vec3 velocity;
float occlusion;
};

extern entityData_t entities[MAX_GENTITIES];

enum EmitterPriority {
ANY,
CLIENT
};

// Tweaks the value given by the audio slider
float SliderToAmplitude(float slider);

Expand Down
Loading
Loading