Skip to content
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

Sound Cleanup #5959

Merged
merged 6 commits into from
Nov 23, 2024
Merged
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
3 changes: 1 addition & 2 deletions src/Player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,7 @@ void Player::StaticUpdate(const float timeStep)
m_creakSound.VolumeAnimate(creakVol, creakVol, 0.3f, 0.3f);
}
} else if (m_creakSound.IsPlaying()) {
m_creakSound.VolumeAnimate(0.0f, 0.0f, 1.5f, 1.5f);
m_creakSound.SetOp(Sound::OP_STOP_AT_TARGET_VOLUME);
m_creakSound.FadeOut(1.5f);
}
m_atmosAccel = current_atmosAccel;

Expand Down
45 changes: 9 additions & 36 deletions src/sound/AmbientSounds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,24 +80,15 @@ void AmbientSounds::Update()

if (Pi::player->GetFlightState() == Ship::DOCKED) {
if (s_starNoise.IsPlaying()) {
const float target[2] = { 0.0f, 0.0f };
const float dv_dt[2] = { 1.0f, 1.0f };
s_starNoise.VolumeAnimate(target, dv_dt);
s_starNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
s_starNoise.FadeOut(1.0f, Sound::OP_REPEAT);
}
for (int i = 0; i < eMaxNumAtmosphereSounds; i++) {
if (s_atmosphereNoises[i].IsPlaying()) {
const float target[2] = { 0.0f, 0.0f };
const float dv_dt[2] = { 1.0f, 1.0f };
s_atmosphereNoises[i].VolumeAnimate(target, dv_dt);
s_atmosphereNoises[i].SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
s_atmosphereNoises[i].FadeOut(1.0f, Sound::OP_REPEAT);
}
}
if (s_planetSurfaceNoise.IsPlaying()) {
const float target[2] = { 0.0f, 0.0f };
const float dv_dt[2] = { 1.0f, 1.0f };
s_planetSurfaceNoise.VolumeAnimate(target, dv_dt);
s_planetSurfaceNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
s_planetSurfaceNoise.FadeOut(1.0f, Sound::OP_REPEAT);
}

if (!s_stationNoise.IsPlaying()) {
Expand All @@ -109,24 +100,15 @@ void AmbientSounds::Update()
} else if (Pi::player->GetFlightState() == Ship::LANDED) {
/* Planet surface noise on rough-landing */
if (s_starNoise.IsPlaying()) {
const float target[2] = { 0.0f, 0.0f };
const float dv_dt[2] = { 1.0f, 1.0f };
s_starNoise.VolumeAnimate(target, dv_dt);
s_starNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
s_starNoise.FadeOut(1.0f, Sound::OP_REPEAT);
}
for (int i = 0; i < eMaxNumAtmosphereSounds; i++) {
if (s_atmosphereNoises[i].IsPlaying()) {
const float target[2] = { 0.0f, 0.0f };
const float dv_dt[2] = { 1.0f, 1.0f };
s_atmosphereNoises[i].VolumeAnimate(target, dv_dt);
s_atmosphereNoises[i].SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
s_atmosphereNoises[i].FadeOut(1.0f, Sound::OP_REPEAT);
}
}
if (s_stationNoise.IsPlaying()) {
const float target[2] = { 0.0f, 0.0f };
const float dv_dt[2] = { 1.0f, 1.0f };
s_stationNoise.VolumeAnimate(target, dv_dt);
s_stationNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
s_stationNoise.FadeOut(1.0f, Sound::OP_REPEAT);
}

// lets try something random for the time being
Expand Down Expand Up @@ -166,20 +148,14 @@ void AmbientSounds::Update()
}
} else {
if (s_stationNoise.IsPlaying()) {
const float target[2] = { 0.0f, 0.0f };
const float dv_dt[2] = { 1.0f, 1.0f };
s_stationNoise.VolumeAnimate(target, dv_dt);
s_stationNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
s_stationNoise.FadeOut(1.0f, Sound::OP_REPEAT);
}
if (Pi::game->IsNormalSpace()) {
StarSystem *s = Pi::game->GetSpace()->GetStarSystem().Get();
if (astroNoiseSeed != s->GetSeed()) {
// change sound!
astroNoiseSeed = s->GetSeed();
const float target[2] = { 0.0f, 0.0f };
const float dv_dt[2] = { 0.1f, 0.1f };
s_starNoise.VolumeAnimate(target, dv_dt);
s_starNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
s_starNoise.FadeOut(0.1f, Sound::OP_REPEAT);
// XXX the way Sound::Event works isn't totally obvious.
// to destroy the object doesn't stop the sound. it is
// really just a sound event reference
Expand Down Expand Up @@ -255,11 +231,8 @@ void AmbientSounds::Update()
}
}
} else {
const float target[2] = { 0.0f, 0.0f };
const float dv_dt[2] = { 1.0f, 1.0f };
for (int i = 0; i < eMaxNumAtmosphereSounds; i++) {
s_atmosphereNoises[i].VolumeAnimate(target, dv_dt);
s_atmosphereNoises[i].SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
s_atmosphereNoises[i].FadeOut(1.0f, Sound::OP_REPEAT);
}
}
}
Expand Down
100 changes: 72 additions & 28 deletions src/sound/Sound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,21 +172,33 @@ namespace Sound {
(*volRightOut) = Clamp((*volRightOut), 0.0f, 1.0f);
}

eventid BodyMakeNoise(const Body *b, const char *sfx, float vol)
void BodyMakeNoise(const Body *b, const char *sfx, float vol)
{
float vl, vr;
CalculateStereo(b, vol, &vl, &vr);
return Sound::PlaySfx(sfx, vl, vr, 0);
Sound::PlaySfx(sfx, vl, vr, 0);
}

struct Sample {
uint16_t *buf;
uint32_t buf_len;
uint32_t channels;
int upsample; // 1 = 44100, 2=22050
/* if buf is null, this will be path to an ogg we must stream */
std::string path;
bool isMusic;
};

typedef uint32_t eventid;

struct SoundEvent {
const Sample *sample;
OggVorbis_File *oggv; // if sample->buf = 0 then stream this
OggFileDataStream ogg_data_stream;
Uint32 buf_pos;
uint32_t buf_pos;
float volume[2]; // left and right channels
eventid identifier;
Uint32 op;
uint32_t op;

float targetVolume[2];
float rateOfChange[2]; // per sample
Expand Down Expand Up @@ -215,20 +227,6 @@ namespace Sound {
return nullptr;
}

bool SetOp(eventid id, Op op)
{
if (id == 0) return false;
bool ret = false;
SDL_LockAudioDevice(m_audioDevice);
SoundEvent *se = GetEvent(id);
if (se) {
se->op = op;
ret = true;
}
SDL_UnlockAudioDevice(m_audioDevice);
return ret;
}

static void DestroyEvent(SoundEvent *ev)
{
if (ev->oggv) {
Expand All @@ -244,12 +242,12 @@ namespace Sound {
/*
* Volume should be 0-65535
*/
static Uint32 identifier = 1;
eventid PlaySfx(const char *fx, const float volume_left, const float volume_right, const Op op)
static uint32_t identifier = 1;
static eventid PlaySfxSample(Sample *sample, const float volume_left, const float volume_right, const Op op)
{
SDL_LockAudioDevice(m_audioDevice);
unsigned int idx;
Uint32 age;
uint32_t age;
/* find free wavstream (first two reserved for music) */
for (idx = 2; idx < MAX_WAVSTREAMS; idx++) {
if (!wavstream[idx].sample) break;
Expand All @@ -266,7 +264,7 @@ namespace Sound {
}
DestroyEvent(&wavstream[idx]);
}
wavstream[idx].sample = GetSample(fx);
wavstream[idx].sample = sample;
wavstream[idx].oggv = 0;
wavstream[idx].buf_pos = 0;
wavstream[idx].volume[0] = volume_left * GetSfxVolume();
Expand All @@ -280,17 +278,25 @@ namespace Sound {
return identifier++;
}

//unlike PlaySfx, we want uninterrupted play and do not care about age
void PlaySfx(const char *fx, const float volume_left, const float volume_right, const Op op)
{
Sample* sample = GetSample(fx);
if (sample) {
PlaySfxSample(sample, volume_left, volume_right, op);
}
}

//unlike PlaySfxSample, we want uninterrupted play and do not care about age
//alternate between two streams for crossfade
static int nextMusicStream = 0;
eventid PlayMusic(const char *fx, const float volume_left, const float volume_right, const Op op)
static eventid PlayMusicSample(Sample *sample, const float volume_left, const float volume_right, const Op op)
{
const int idx = nextMusicStream;
nextMusicStream ^= 1;
SDL_LockAudioDevice(m_audioDevice);
if (wavstream[idx].sample)
DestroyEvent(&wavstream[idx]);
wavstream[idx].sample = GetSample(fx);
wavstream[idx].sample = sample;
wavstream[idx].oggv = nullptr;
wavstream[idx].buf_pos = 0;
wavstream[idx].volume[0] = volume_left;
Expand Down Expand Up @@ -690,7 +696,30 @@ namespace Sound {
void Event::Play(const char *fx, float volume_left, float volume_right, Op op)
{
Stop();
eid = PlaySfx(fx, volume_left, volume_right, op);
Sample* sample = GetSample(fx);
if (sample) {
eid = PlaySfxSample(sample, volume_left, volume_right, op);
}
}

void Event::PlayMusic(const char *fx, float volume, float fadeDelta, bool repeat, Event* fadeOut)
{
// The FadeOut, Stop, PlayMusicSample & VolumeAnimate calls perform
// five mutex lock operations. These could be reduced to a single
// lock/unlock if this were re-written.

if (fadeOut) {
fadeOut->FadeOut(fadeDelta);
}
Stop();
Sample* sample = GetSample(fx);
if (sample) {
float start = fadeDelta ? 0.0f : volume;
eid = PlayMusicSample(sample, start, start, repeat ? Sound::OP_REPEAT : 0);
if (fadeDelta) {
VolumeAnimate(volume, volume, fadeDelta, fadeDelta);
}
}
}

bool Event::Stop()
Expand Down Expand Up @@ -762,9 +791,24 @@ namespace Sound {
return status;
}

const std::map<std::string, Sample> &GetSamples()
bool Event::FadeOut(float dv_dt, Op op)
{
bool found = VolumeAnimate(0.0f, 0.0f, dv_dt, dv_dt);
if (found)
SetOp(op | Sound::OP_STOP_AT_TARGET_VOLUME);
return found;
}

const std::vector<std::string> GetMusicFiles()
{
return sfx_samples;
std::vector<std::string> songs;
songs.reserve(sfx_samples.size());
for (std::map<std::string, Sample>::const_iterator it = sfx_samples.begin();
it != sfx_samples.end(); ++it) {
if (it->second.isMusic)
songs.emplace_back(it->first.c_str());
}
return songs;
}

} /* namespace Sound */
41 changes: 14 additions & 27 deletions src/sound/Sound.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// Copyright © 2008-2024 Pioneer Developers. See AUTHORS.txt for details
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt

#ifndef __OGGMIX_H
#define __OGGMIX_H
#ifndef __SOUND_H
#define __SOUND_H

#include <SDL_stdinc.h>
#include <cstdint>
#include <map>
#include <string>
#include <vector>
Expand All @@ -17,29 +17,17 @@ namespace Sound {
OP_REPEAT = (1 << 0),
OP_STOP_AT_TARGET_VOLUME = (1 << 1)
};
typedef Uint32 Op;

struct Sample {
Uint16 *buf;
Uint32 buf_len;
Uint32 channels;
int upsample; // 1 = 44100, 2=22050
/* if buf is null, this will be path to an ogg we must stream */
std::string path;
bool isMusic;
};
typedef uint32_t Op;

class Event {
public:
Event() :
eid(0) {}
Event(Uint32 id) :
eid(id) {}
virtual void Play(const char *fx, const float volume_left, const float volume_right, Op op);
void Play(const char *fx, const float volume_left, const float volume_right, Op op);
void Play(const char *fx) { Play(fx, 1.0f, 1.0f, 0); }
void PlayMusic(const char *fx, float volume, float fadeDelta, bool repeat, Event* fadeOut = nullptr);
bool Stop();
bool IsPlaying() const;
Uint32 EventId() { return eid; }
bool SetOp(Op op);
bool VolumeAnimate(const float targetVol1, const float targetVol2, const float dv_dt1, const float dv_dt2);
bool VolumeAnimate(const float targetVols[2], const float dv_dt[2])
Expand All @@ -52,11 +40,11 @@ namespace Sound {
{
return SetVolume(vol, vol);
}
bool FadeOut(float dv_dt, Op op = 0);

protected:
Uint32 eid;
private:
uint32_t eid;
};
typedef Uint32 eventid;

bool Init(bool automaticallyOpenDevice = true);
bool InitDevice(std::string &name);
Expand All @@ -69,17 +57,16 @@ namespace Sound {
void DestroyAllEvents();
void DestroyAllEventsExceptMusic();
void Pause(int on);
eventid PlaySfx(const char *fx, const float volume_left, const float volume_right, const Op op);
eventid PlayMusic(const char *fx, const float volume_left, const float volume_right, const Op op);
inline static eventid PlaySfx(const char *fx) { return PlaySfx(fx, 1.0f, 1.0f, 0); }
void PlaySfx(const char *fx, const float volume_left, const float volume_right, const Op op);
inline static void PlaySfx(const char *fx) { PlaySfx(fx, 1.0f, 1.0f, 0); }
void CalculateStereo(const Body *b, float vol, float *volLeftOut, float *volRightOut);
eventid BodyMakeNoise(const Body *b, const char *fx, float vol);
void BodyMakeNoise(const Body *b, const char *fx, float vol);
void SetMasterVolume(const float vol);
float GetMasterVolume();
void SetSfxVolume(const float vol);
float GetSfxVolume();
const std::map<std::string, Sample> &GetSamples();
const std::vector<std::string> GetMusicFiles();

} /* namespace Sound */

#endif /* __OGGMIX_H */
#endif /* __SOUND_H */
Loading