1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-07-02 16:38:41 +00:00

Sound refactor and improvements (#12764)

This commit is contained in:
DS 2023-06-16 20:15:21 +02:00 committed by GitHub
parent 8e1af25738
commit edcbfa31c9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 2802 additions and 1211 deletions

View file

@ -19,72 +19,168 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
#include <set>
#include <string>
#include "irr_v3d.h"
#include "../sound.h"
#include <limits>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
class OnDemandSoundFetcher
struct SoundSpec;
class SoundFallbackPathProvider
{
public:
virtual void fetchSounds(const std::string &name,
std::set<std::string> &dst_paths,
std::set<std::string> &dst_datas) = 0;
virtual ~SoundFallbackPathProvider() = default;
std::vector<std::string> getLocalFallbackPathsForSoundname(const std::string &name);
protected:
virtual void addThePaths(const std::string &name, std::vector<std::string> &paths);
// adds <common>.ogg, <common>.1.ogg, ..., <common>.9.ogg to paths
void addAllAlternatives(const std::string &common, std::vector<std::string> &paths);
private:
std::unordered_set<std::string> m_done_names;
};
/**
* IDs for playing sounds.
* 0 is for sounds that are never modified after creation.
* Negative numbers are invalid.
* Positive numbers are allocated via allocateId and are manually reference-counted.
*/
using sound_handle_t = int;
constexpr sound_handle_t SOUND_HANDLE_T_MAX = std::numeric_limits<sound_handle_t>::max();
class ISoundManager
{
private:
std::unordered_map<sound_handle_t, u32> m_occupied_ids;
sound_handle_t m_next_id = 1;
std::vector<sound_handle_t> m_removed_sounds;
protected:
void reportRemovedSound(sound_handle_t id);
public:
virtual ~ISoundManager() = default;
// Multiple sounds can be loaded per name; when played, the sound
// should be chosen randomly from alternatives
// Return value determines success/failure
virtual bool loadSoundFile(
const std::string &name, const std::string &filepath) = 0;
virtual bool loadSoundData(
const std::string &name, const std::string &filedata) = 0;
/**
* Removes finished sounds, steps streamed sounds, and does similar tasks.
* Should not be called while paused.
* @param dtime In seconds.
*/
virtual void step(f32 dtime) = 0;
/**
* Pause all sound playback.
*/
virtual void pauseAll() = 0;
/**
* Resume sound playback after pause.
*/
virtual void resumeAll() = 0;
virtual void updateListener(
const v3f &pos, const v3f &vel, const v3f &at, const v3f &up) = 0;
virtual void setListenerGain(float gain) = 0;
/**
* @param pos In node-space.
* @param vel In node-space.
* @param at Vector in node-space pointing forwards.
* @param up Vector in node-space pointing upwards, orthogonal to `at`.
*/
virtual void updateListener(const v3f &pos, const v3f &vel, const v3f &at,
const v3f &up) = 0;
virtual void setListenerGain(f32 gain) = 0;
// playSound functions return -1 on failure, otherwise a handle to the
// sound. If name=="", call should be ignored without error.
virtual int playSound(const SimpleSoundSpec &spec) = 0;
virtual int playSoundAt(const SimpleSoundSpec &spec, const v3f &pos) = 0;
virtual void stopSound(int sound) = 0;
virtual bool soundExists(int sound) = 0;
virtual void updateSoundPosition(int sound, v3f pos) = 0;
virtual bool updateSoundGain(int id, float gain) = 0;
virtual float getSoundGain(int id) = 0;
virtual void step(float dtime) = 0;
virtual void fadeSound(int sound, float step, float gain) = 0;
/**
* Adds a sound to load from a file (only OggVorbis).
* @param name The name of the sound. Must be unique, otherwise call fails.
* @param filepath The path for
* @return true on success, false on failure (ie. sound was already added or
* file does not exist).
*/
virtual bool loadSoundFile(const std::string &name, const std::string &filepath) = 0;
/**
* Same as `loadSoundFile`, but reads the OggVorbis file from memory.
*/
virtual bool loadSoundData(const std::string &name, std::string &&filedata) = 0;
/**
* Adds sound with name sound_name to group `group_name`. Creates the group
* if non-existent.
* @param sound_name The name of the sound, as used in `loadSoundData`.
* @param group_name The name of the sound group.
*/
virtual void addSoundToGroup(const std::string &sound_name,
const std::string &group_name) = 0;
/**
* Plays a random sound from a sound group (position-less).
* @param id Id for new sound. Move semantics apply if id > 0.
*/
virtual void playSound(sound_handle_t id, const SoundSpec &spec) = 0;
/**
* Same as `playSound`, but at a position.
* @param pos In node-space.
* @param vel In node-space.
*/
virtual void playSoundAt(sound_handle_t id, const SoundSpec &spec, const v3f &pos,
const v3f &vel) = 0;
/**
* Request the sound to be stopped.
* The id should be freed afterwards.
*/
virtual void stopSound(sound_handle_t sound) = 0;
virtual void fadeSound(sound_handle_t sound, f32 step, f32 target_gain) = 0;
/**
* Update position and velocity of positional sound.
* @param pos In node-space.
* @param vel In node-space.
*/
virtual void updateSoundPosVel(sound_handle_t sound, const v3f &pos,
const v3f &vel) = 0;
/**
* Get and reset the list of sounds that were stopped.
*/
std::vector<sound_handle_t> pollRemovedSounds()
{
std::vector<sound_handle_t> ret;
std::swap(m_removed_sounds, ret);
return ret;
}
/**
* Returns a positive id.
* The id will be returned again until freeId is called.
* @param num_owners Owner-counter for id. Set this to 2, if you want to play
* a sound and store the id also otherwhere.
*/
sound_handle_t allocateId(u32 num_owners);
/**
* Free an id allocated via allocateId.
* @param num_owners How much the owner-counter should be decreased. Id can
* be reused when counter reaches 0.
*/
void freeId(sound_handle_t id, u32 num_owners = 1);
};
class DummySoundManager : public ISoundManager
class DummySoundManager final : public ISoundManager
{
public:
virtual bool loadSoundFile(const std::string &name, const std::string &filepath)
{
return true;
}
virtual bool loadSoundData(const std::string &name, const std::string &filedata)
{
return true;
}
void updateListener(const v3f &pos, const v3f &vel, const v3f &at, const v3f &up)
{
}
void setListenerGain(float gain) {}
void step(f32 dtime) override {}
void pauseAll() override {}
void resumeAll() override {}
int playSound(const SimpleSoundSpec &spec) { return -1; }
int playSoundAt(const SimpleSoundSpec &spec, const v3f &pos) { return -1; }
void stopSound(int sound) {}
bool soundExists(int sound) { return false; }
void updateSoundPosition(int sound, v3f pos) {}
bool updateSoundGain(int id, float gain) { return false; }
float getSoundGain(int id) { return 0; }
void step(float dtime) {}
void fadeSound(int sound, float step, float gain) {}
void updateListener(const v3f &pos, const v3f &vel, const v3f &at, const v3f &up) override {}
void setListenerGain(f32 gain) override {}
bool loadSoundFile(const std::string &name, const std::string &filepath) override { return true; }
bool loadSoundData(const std::string &name, std::string &&filedata) override { return true; }
void addSoundToGroup(const std::string &sound_name, const std::string &group_name) override {};
void playSound(sound_handle_t id, const SoundSpec &spec) override { reportRemovedSound(id); }
void playSoundAt(sound_handle_t id, const SoundSpec &spec, const v3f &pos,
const v3f &vel) override { reportRemovedSound(id); }
void stopSound(sound_handle_t sound) override {}
void fadeSound(sound_handle_t sound, f32 step, f32 target_gain) override {}
void updateSoundPosVel(sound_handle_t sound, const v3f &pos, const v3f &vel) override {}
};