audio: share decoded clip cache across sources

This commit is contained in:
2026-04-14 16:17:17 +08:00
parent 5de4848d70
commit 4b58df9a61
7 changed files with 1646 additions and 145 deletions

View File

@@ -2,7 +2,10 @@
#include <XCEngine/Components/Component.h>
#include <XCEngine/Components/TransformComponent.h>
#include <XCEngine/Audio/HRTF.h>
#include <XCEngine/Audio/AudioTypes.h>
#include <XCEngine/Core/Asset/AssetRef.h>
#include <XCEngine/Core/Asset/ResourceHandle.h>
#include <XCEngine/Resources/AudioClip/AudioClip.h>
#include <XCEngine/Core/Math/Vector3.h>
#include <XCEngine/Core/Math/Quaternion.h>
@@ -30,6 +33,10 @@ public:
void SetClip(Resources::AudioClip* clip);
Resources::AudioClip* GetClip() const { return m_clip; }
void SetClipPath(const std::string& clipPath);
void ClearClip();
const std::string& GetClipPath() const { return m_clipPath; }
const Resources::AssetRef& GetClipAssetRef() const { return m_clipRef; }
void SetVolume(float volume);
float GetVolume() const { return m_volume; }
@@ -40,6 +47,13 @@ public:
void SetPan(float pan);
float GetPan() const { return m_pan; }
void SetHRTFEnabled(bool enabled);
bool IsHRTFEnabled() const { return m_useHRTF; }
void SetHRTFCrossFeed(float crossFeed);
float GetHRTFCrossFeed() const { return m_hrtf.GetCrossFeed(); }
void SetHRTFQuality(Audio::uint32 level);
Audio::uint32 GetHRTFQuality() const { return m_hrtf.GetQualityLevel(); }
void SetLooping(bool loop);
bool IsLooping() const { return m_isLooping; }
@@ -74,20 +88,34 @@ public:
void OnEnable() override;
void OnDisable() override;
void OnDestroy() override;
void Serialize(std::ostream& os) const override;
void Deserialize(std::istream& is) override;
void ProcessAudio(float* buffer, Audio::uint32 sampleCount, Audio::uint32 channels,
void ProcessAudio(float* buffer, Audio::uint32 frameCount, Audio::uint32 channels,
const Math::Vector3& listenerPosition,
const Math::Quaternion& listenerRotation);
const Math::Quaternion& listenerRotation,
const Math::Vector3& listenerVelocity = Math::Vector3::Zero(),
float listenerDopplerLevel = 1.0f,
float speedOfSound = 343.0f,
Audio::uint32 outputSampleRate = 0);
std::string GetName() const override { return "AudioSource"; }
private:
void DecodeAudioData();
void Apply3DAttenuation(const Math::Vector3& listenerPosition);
float Compute3DAttenuation(const Math::Vector3& listenerPosition) const;
float ComputeSpatialPan(const Math::Vector3& listenerPosition,
const Math::Quaternion& listenerRotation) const;
double ComputeDopplerFactor(const Math::Vector3& listenerPosition,
const Math::Vector3& listenerVelocity,
float listenerDopplerLevel,
float speedOfSound) const;
void UpdateEnergy(const float* buffer, Audio::uint32 sampleCount);
private:
Resources::ResourceHandle<Resources::AudioClip> m_clipHandle;
Resources::AudioClip* m_clip = nullptr;
std::string m_clipPath;
Resources::AssetRef m_clipRef;
Audio::AudioMixer* m_outputMixer = nullptr;
Audio::PlayState m_playState = Audio::PlayState::Stopped;
@@ -97,21 +125,22 @@ private:
float m_pitch = 1.0f;
float m_pan = 0.0f;
bool m_spatialize = true;
bool m_useHRTF = false;
Audio::Audio3DParams m_3DParams;
Audio::HRTF m_hrtf;
Audio::uint64 m_samplePosition = 0;
double m_playbackPosition = 0.0;
double m_lastingTime = 0.0;
Math::Vector3 m_velocity = Math::Vector3::Zero();
Math::Vector3 m_lastPosition = Math::Vector3::Zero();
bool m_hasLastPosition = false;
bool m_isEnergyDetecting = false;
float m_energy = 0.0f;
float m_maxEnergy = 5.0f;
std::deque<float> m_energyHistory;
static constexpr size_t BufferSize = 8192;
std::vector<float> m_outputBuffer;
std::vector<float> m_decodedData;
bool m_isDecoded = false;
};
} // namespace Components

View File

@@ -3,6 +3,7 @@
#include <XCEngine/Core/Asset/IResource.h>
#include <XCEngine/Core/Containers/Array.h>
#include <XCEngine/Core/Types.h>
#include <vector>
namespace XCEngine {
namespace Resources {
@@ -35,20 +36,31 @@ public:
size_t GetMemorySize() const override { return m_memorySize; }
void Release() override;
void SetAudioData(const Containers::Array<Core::uint8>& data);
const Containers::Array<Core::uint8>& GetAudioData() const { return m_audioData; }
void SetPCMData(const Containers::Array<Core::uint8>& data);
const Containers::Array<Core::uint8>& GetPCMData() const { return m_pcmData; }
size_t GetPCMDataSize() const { return m_pcmData.Size(); }
// Legacy compatibility: audio data now means decoded/interpretable PCM bytes.
void SetAudioData(const Containers::Array<Core::uint8>& data) { SetPCMData(data); }
const Containers::Array<Core::uint8>& GetAudioData() const { return GetPCMData(); }
void SetSampleRate(Core::uint32 rate) { m_sampleRate = rate; }
void SetSampleRate(Core::uint32 rate);
Core::uint32 GetSampleRate() const { return m_sampleRate; }
void SetChannels(Core::uint32 channels) { m_channels = channels; }
void SetChannels(Core::uint32 channels);
Core::uint32 GetChannels() const { return m_channels; }
void SetBitsPerSample(Core::uint32 bits) { m_bitsPerSample = bits; }
void SetBitsPerSample(Core::uint32 bits);
Core::uint32 GetBitsPerSample() const { return m_bitsPerSample; }
void SetDuration(float seconds) { m_duration = seconds; }
float GetDuration() const { return m_duration; }
const std::vector<float>& GetDecodedPCMData() const;
bool HasDecodedPCMData() const { return m_decodedPCMValid; }
Core::uint64 GetFrameCount() const;
Core::uint64 GetSampleCount() const;
void SetAudioFormat(AudioFormat format) { m_format = format; }
AudioFormat GetAudioFormat() const { return m_format; }
@@ -66,7 +78,14 @@ public:
void SetRHIResource(class IRHIAudioBuffer* resource);
private:
Containers::Array<Core::uint8> m_audioData;
void RefreshDerivedData();
void RefreshMemorySize();
void InvalidateDecodedPCMData();
void BuildDecodedPCMData() const;
Containers::Array<Core::uint8> m_pcmData;
mutable std::vector<float> m_decodedPCMData;
mutable bool m_decodedPCMValid = false;
Core::uint32 m_sampleRate = 44100;
Core::uint32 m_channels = 2;