feat: add audio system
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -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) \
|
||||
|
||||
Reference in New Issue
Block a user