feat: add audio system

This commit is contained in:
2026-10-23 22:07:52 +02:00
parent a3d3da4a67
commit 0b7cc38543
28 changed files with 7412 additions and 214 deletions
@@ -29,6 +29,7 @@ namespace AssetTypes {
[[nodiscard]] inline bool IsModel(std::string_view path) { return HasExtension(path, {".fbx", ".glb", ".gltf", ".obj"}); }
[[nodiscard]] inline bool IsImage(std::string_view path) { return HasExtension(path, {".png", ".jpg", ".jpeg", ".tga", ".bmp"}); }
[[nodiscard]] inline bool IsAudio(std::string_view path) { return HasExtension(path, {".wav", ".ogg"}); }
[[nodiscard]] inline bool IsMaterial(std::string_view path) { return HasExtension(path, {MaterialExtension}); }
[[nodiscard]] inline bool IsScene(std::string_view path) { return HasExtension(path, {SceneExtension}); }
[[nodiscard]] inline bool IsPrefab(std::string_view path) { return HasExtension(path, {PrefabExtension}); }
@@ -0,0 +1,31 @@
#ifndef DESTRUM_AUDIODECODER_H
#define DESTRUM_AUDIODECODER_H
#include <cstdint>
#include <optional>
#include <span>
#include <string_view>
#include <vector>
struct AudioData {
int channels{0};
int sampleRate{0};
std::vector<std::int16_t> samples;
[[nodiscard]] float Duration() const
{
if (channels <= 0 || sampleRate <= 0) {
return 0.0f;
}
return static_cast<float>(samples.size() / static_cast<std::size_t>(channels)) / static_cast<float>(sampleRate);
}
};
namespace AudioDecoder {
[[nodiscard]] std::optional<AudioData> DecodeWav(std::span<const std::uint8_t> bytes);
[[nodiscard]] std::optional<AudioData> DecodeOgg(std::span<const std::uint8_t> bytes);
[[nodiscard]] std::optional<AudioData> Decode(std::span<const std::uint8_t> bytes, std::string_view path);
}
#endif // DESTRUM_AUDIODECODER_H
+111
View File
@@ -0,0 +1,111 @@
#ifndef DESTRUM_AUDIOSYSTEM_H
#define DESTRUM_AUDIOSYSTEM_H
#include <cstdint>
#include <memory>
#include <string>
#include <string_view>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <glm/glm.hpp>
#include <destrum/Singleton.h>
struct AudioData;
struct ALCdevice;
struct ALCcontext;
class Camera;
class AudioClip {
public:
AudioClip(std::string path, std::uint32_t buffer, int channels, int sampleRate, float duration);
~AudioClip();
AudioClip(const AudioClip&) = delete;
AudioClip& operator=(const AudioClip&) = delete;
[[nodiscard]] const std::string& GetPath() const { return m_Path; }
[[nodiscard]] std::uint32_t GetBuffer() const { return m_Buffer; }
[[nodiscard]] int GetChannels() const { return m_Channels; }
[[nodiscard]] int GetSampleRate() const { return m_SampleRate; }
[[nodiscard]] float GetDuration() const { return m_Duration; }
private:
std::string m_Path;
std::uint32_t m_Buffer{0};
int m_Channels{0};
int m_SampleRate{0};
float m_Duration{0.0f};
};
[[nodiscard]] glm::vec3 SmoothAudioVelocity(const glm::vec3& current, const glm::vec3& previous,
const glm::vec3& smoothed, float dt);
struct OneShotParams {
float volume{1.0f};
float pitch{1.0f};
bool spatial{true};
float minDistance{1.0f};
float maxDistance{50.0f};
};
class AudioSystem final : public Singleton<AudioSystem> {
public:
friend class Singleton<AudioSystem>;
~AudioSystem() override;
bool Init();
void Shutdown();
[[nodiscard]] bool IsAvailable() const { return m_Context != nullptr; }
std::shared_ptr<const AudioClip> LoadClip(std::string_view vpath);
std::shared_ptr<const AudioClip> CreateClip(std::string path, const AudioData& data);
void ReleaseUnusedClips();
std::uint32_t CreateSource();
void DestroySource(std::uint32_t source);
void PlayOneShot(std::string_view vpath, const glm::vec3& position, const OneShotParams& params = {});
void SetListener(const glm::vec3& position, const glm::vec3& forward, const glm::vec3& up);
void Update(float dt, bool paused, const Camera* fallbackListener);
void SetMasterVolume(float volume);
[[nodiscard]] float GetMasterVolume() const { return m_MasterVolume; }
[[nodiscard]] bool IsPaused() const { return m_Paused; }
private:
AudioSystem() = default;
void SetPaused(bool paused);
struct OneShot {
std::uint32_t source{0};
std::shared_ptr<const AudioClip> clip;
};
ALCdevice* m_Device{nullptr};
ALCcontext* m_Context{nullptr};
std::unordered_map<std::string, std::shared_ptr<const AudioClip>> m_Clips;
std::unordered_set<std::uint32_t> m_Sources;
std::vector<std::uint32_t> m_PausedSources;
std::vector<OneShot> m_OneShots;
glm::vec3 m_ListenerPosition{0.0f};
glm::vec3 m_ListenerForward{0.0f, 0.0f, -1.0f};
glm::vec3 m_ListenerUp{0.0f, 1.0f, 0.0f};
glm::vec3 m_LastListenerPosition{0.0f};
glm::vec3 m_ListenerVelocity{0.0f};
bool m_HasLastListenerPosition{false};
bool m_ListenerSetThisFrame{false};
float m_MasterVolume{1.0f};
bool m_Paused{false};
};
#endif // DESTRUM_AUDIOSYSTEM_H
@@ -0,0 +1,22 @@
#ifndef DESTRUM_AUDIOLISTENER_H
#define DESTRUM_AUDIOLISTENER_H
#include <destrum/ObjectModel/Component.h>
class AudioListener final : public Component {
public:
explicit AudioListener(GameObject& parent);
AudioListener(const AudioListener& other) = delete;
AudioListener(AudioListener&& other) noexcept = delete;
AudioListener& operator=(const AudioListener& other) = delete;
AudioListener& operator=(AudioListener&& other) noexcept = delete;
void LateUpdate(float dt) override;
std::string GetTypeName() const override { return "AudioListener"; }
void ImGuiInspector() override;
};
#endif // DESTRUM_AUDIOLISTENER_H
@@ -0,0 +1,86 @@
#ifndef DESTRUM_AUDIOSOURCE_H
#define DESTRUM_AUDIOSOURCE_H
#include <cstdint>
#include <memory>
#include <string>
#include <glm/glm.hpp>
#include <destrum/ObjectModel/Component.h>
class AudioClip;
class AudioSource final : public Component {
public:
explicit AudioSource(GameObject& parent, std::string clipPath = {});
~AudioSource() override;
AudioSource(const AudioSource& other) = delete;
AudioSource(AudioSource&& other) noexcept = delete;
AudioSource& operator=(const AudioSource& other) = delete;
AudioSource& operator=(AudioSource&& other) noexcept = delete;
void Update(float dt) override;
void LateUpdate(float dt) override;
void SetEnabled(bool enabled) override;
std::string GetTypeName() const override { return "AudioSource"; }
nlohmann::json Serialize() const override;
void Deserialize(const nlohmann::json& data) override;
void ImGuiInspector() override;
void Play();
void Pause();
void Stop();
[[nodiscard]] bool IsPlaying() const;
void PlayOneShot(const std::string& clipPath, float volumeScale = 1.0f) const;
void SetClip(const std::string& clipPath);
[[nodiscard]] const std::string& GetClip() const { return m_ClipPath; }
void SetVolume(float volume);
[[nodiscard]] float GetVolume() const { return m_Volume; }
void SetPitch(float pitch);
[[nodiscard]] float GetPitch() const { return m_Pitch; }
void SetLoop(bool loop);
[[nodiscard]] bool GetLoop() const { return m_Loop; }
void SetPlayOnStart(bool playOnStart) { m_PlayOnStart = playOnStart; }
[[nodiscard]] bool GetPlayOnStart() const { return m_PlayOnStart; }
void SetSpatial(bool spatial);
[[nodiscard]] bool GetSpatial() const { return m_Spatial; }
void SetDistances(float minDistance, float maxDistance);
[[nodiscard]] float GetMinDistance() const { return m_MinDistance; }
[[nodiscard]] float GetMaxDistance() const { return m_MaxDistance; }
private:
bool EnsureSource();
void ApplyProperties();
void SyncPosition(float dt);
void ReleaseSource();
std::string m_ClipPath;
float m_Volume{1.0f};
float m_Pitch{1.0f};
bool m_Loop{false};
bool m_PlayOnStart{true};
bool m_Spatial{true};
float m_MinDistance{1.0f};
float m_MaxDistance{50.0f};
std::uint32_t m_Source{0};
std::shared_ptr<const AudioClip> m_Clip;
bool m_AutoPlayed{false};
glm::vec3 m_LastPosition{0.0f};
glm::vec3 m_Velocity{0.0f};
bool m_HasLastPosition{false};
};
#endif // DESTRUM_AUDIOSOURCE_H
+1
View File
@@ -25,6 +25,7 @@ public:
void Init(std::filesystem::path exeDir);
void Reset();
void Mount(std::string scheme, std::filesystem::path root);
void ReloadManifest(std::string_view scheme);
std::vector<uint8_t> ReadBytes(std::string_view vpath);
@@ -2,6 +2,8 @@
#define DESTRUM_ENGINECOMPONENTLIST_H
#include <destrum/Components/Animator.h>
#include <destrum/Components/AudioListener.h>
#include <destrum/Components/AudioSource.h>
#include <destrum/Components/CameraComponent.h>
#include <destrum/Components/LightComponent.h>
#include <destrum/Components/MeshRendererComponent.h>
@@ -25,6 +27,8 @@
X(Spinner) \
X(OrbitAndSpin) \
X(Animator) \
X(AudioSource) \
X(AudioListener) \
X(Rigidbody) \
X(BoxCollider) \
X(SphereCollider) \