diff --git a/src/Player.cpp b/src/Player.cpp index e8b3f25976..f3754e4b2a 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -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; diff --git a/src/sound/AmbientSounds.cpp b/src/sound/AmbientSounds.cpp index 0799e84e7e..ba3abd66d1 100644 --- a/src/sound/AmbientSounds.cpp +++ b/src/sound/AmbientSounds.cpp @@ -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()) { @@ -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 @@ -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 @@ -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); } } } diff --git a/src/sound/Sound.cpp b/src/sound/Sound.cpp index 4ec6f4f05a..832e708004 100644 --- a/src/sound/Sound.cpp +++ b/src/sound/Sound.cpp @@ -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 @@ -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) { @@ -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; @@ -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(); @@ -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; @@ -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() @@ -762,9 +791,24 @@ namespace Sound { return status; } - const std::map &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 GetMusicFiles() { - return sfx_samples; + std::vector songs; + songs.reserve(sfx_samples.size()); + for (std::map::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 */ diff --git a/src/sound/Sound.h b/src/sound/Sound.h index 10c2539668..8c45cff7fe 100644 --- a/src/sound/Sound.h +++ b/src/sound/Sound.h @@ -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 +#include #include #include #include @@ -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]) @@ -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); @@ -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 &GetSamples(); + const std::vector GetMusicFiles(); } /* namespace Sound */ -#endif /* __OGGMIX_H */ +#endif /* __SOUND_H */ diff --git a/src/sound/SoundMusic.cpp b/src/sound/SoundMusic.cpp index e33cfce3dc..6414b0565a 100644 --- a/src/sound/SoundMusic.cpp +++ b/src/sound/SoundMusic.cpp @@ -8,20 +8,6 @@ namespace Sound { - MusicEvent::MusicEvent() : - Event() {} - - MusicEvent::MusicEvent(Uint32 id) : - Event(id) {} - - MusicEvent::~MusicEvent() {} - - void MusicEvent::Play(const char *fx, const float volume_left, const float volume_right, Op op) - { - Stop(); - eid = PlayMusic(fx, volume_left, volume_right, op); - } - MusicPlayer::MusicPlayer() : m_volume(0.8f), m_playing(false), @@ -53,22 +39,18 @@ namespace Sound { void MusicPlayer::Play(const std::string &name, const bool repeat /* = false */, const float fadeDelta /* = 1.f */) { if (!m_enabled) return; - Sound::Op op = 0; - if (repeat) - op |= Sound::OP_REPEAT; + + Event *current, *next; if (m_eventOnePlaying) { - m_eventOne.VolumeAnimate(0.f, 0.f, fadeDelta, fadeDelta); - m_eventOne.SetOp(Sound::OP_STOP_AT_TARGET_VOLUME); - m_eventTwo.Play(name.c_str(), 0.f, 0.f, op); - m_eventTwo.VolumeAnimate(m_volume, m_volume, fadeDelta, fadeDelta); m_eventOnePlaying = false; + current = &m_eventOne; + next = &m_eventTwo; } else { - m_eventTwo.VolumeAnimate(0.f, 0.f, fadeDelta, fadeDelta); - m_eventTwo.SetOp(Sound::OP_STOP_AT_TARGET_VOLUME); - m_eventOne.Play(name.c_str(), 0.f, 0.f, op); - m_eventOne.VolumeAnimate(m_volume, m_volume, fadeDelta, fadeDelta); m_eventOnePlaying = true; + current = &m_eventTwo; + next = &m_eventOne; } + next->PlayMusic(name.c_str(), m_volume, repeat, fadeDelta, current); m_playing = true; m_currentSongName = name; } @@ -83,11 +65,9 @@ namespace Sound { void MusicPlayer::FadeOut(const float fadeDelta) { if (m_eventOnePlaying) { //2 might be already fading out - m_eventOne.SetOp(Sound::OP_STOP_AT_TARGET_VOLUME); - m_eventOne.VolumeAnimate(0.f, 0.f, fadeDelta, fadeDelta); + m_eventOne.FadeOut(fadeDelta); } else { // 1 might be already fading out - m_eventTwo.SetOp(Sound::OP_STOP_AT_TARGET_VOLUME); - m_eventTwo.VolumeAnimate(0.f, 0.f, fadeDelta, fadeDelta); + m_eventTwo.FadeOut(fadeDelta); } } @@ -109,18 +89,7 @@ namespace Sound { const std::vector MusicPlayer::GetSongList() const { - using std::pair; - using std::string; - const std::map samples = Sound::GetSamples(); - std::vector songs; - songs.reserve(samples.size()); - for (std::map::const_iterator it = samples.begin(); - it != samples.end(); ++it) { - if (it->second.isMusic) - songs.emplace_back(it->first.c_str()); - } - - return songs; + return GetMusicFiles(); } bool MusicPlayer::IsPlaying() const diff --git a/src/sound/SoundMusic.h b/src/sound/SoundMusic.h index 493201baba..b08c8af85c 100644 --- a/src/sound/SoundMusic.h +++ b/src/sound/SoundMusic.h @@ -11,14 +11,6 @@ #include namespace Sound { - class MusicEvent : public Event { - public: - MusicEvent(); - MusicEvent(Uint32 id); - ~MusicEvent(); - virtual void Play(const char *fx, const float volume_left, const float volume_right, Op op); - }; - class MusicPlayer { public: MusicPlayer(); @@ -39,8 +31,8 @@ namespace Sound { private: float m_volume; //two streams for crossfade - MusicEvent m_eventOne; - MusicEvent m_eventTwo; + Event m_eventOne; + Event m_eventTwo; bool m_playing; bool m_eventOnePlaying; std::string m_currentSongName;