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

@@ -8,19 +8,151 @@ AudioClip::AudioClip() = default;
AudioClip::~AudioClip() = default;
void AudioClip::Release() {
m_audioData.Clear();
m_pcmData.Clear();
m_decodedPCMData.clear();
m_decodedPCMValid = false;
m_rhiResource = nullptr;
m_sampleRate = 44100;
m_channels = 2;
m_bitsPerSample = 16;
m_duration = 0.0f;
m_format = AudioFormat::Unknown;
m_audioType = AudioType::SoundEffect;
m_is3D = false;
m_loop = false;
m_isValid = false;
m_memorySize = 0;
}
void AudioClip::SetAudioData(const Containers::Array<Core::uint8>& data) {
m_audioData = data;
if (m_sampleRate > 0 && m_channels > 0 && m_bitsPerSample > 0) {
size_t bytesPerSample = m_bitsPerSample / 8;
size_t totalSamples = data.Size() / bytesPerSample;
m_duration = static_cast<float>(totalSamples) / static_cast<float>(m_sampleRate);
void AudioClip::SetPCMData(const Containers::Array<Core::uint8>& data) {
m_pcmData = data;
InvalidateDecodedPCMData();
RefreshDerivedData();
}
void AudioClip::SetSampleRate(Core::uint32 rate) {
m_sampleRate = rate;
InvalidateDecodedPCMData();
RefreshDerivedData();
}
void AudioClip::SetChannels(Core::uint32 channels) {
m_channels = channels;
InvalidateDecodedPCMData();
RefreshDerivedData();
}
void AudioClip::SetBitsPerSample(Core::uint32 bits) {
m_bitsPerSample = bits;
InvalidateDecodedPCMData();
RefreshDerivedData();
}
const std::vector<float>& AudioClip::GetDecodedPCMData() const {
if (!m_decodedPCMValid) {
BuildDecodedPCMData();
}
return m_decodedPCMData;
}
void AudioClip::RefreshDerivedData() {
if (m_sampleRate > 0 && m_channels > 0 && m_bitsPerSample > 0) {
const size_t bytesPerFrame =
static_cast<size_t>(m_channels) * (static_cast<size_t>(m_bitsPerSample) / 8u);
if (bytesPerFrame > 0) {
const size_t totalFrames = m_pcmData.Size() / bytesPerFrame;
m_duration = static_cast<float>(totalFrames) / static_cast<float>(m_sampleRate);
RefreshMemorySize();
return;
}
}
m_duration = 0.0f;
RefreshMemorySize();
}
void AudioClip::RefreshMemorySize() {
m_memorySize = sizeof(AudioClip) +
m_name.Length() +
m_path.Length() +
m_pcmData.Size() +
m_decodedPCMData.size() * sizeof(float);
}
void AudioClip::InvalidateDecodedPCMData() {
m_decodedPCMData.clear();
m_decodedPCMValid = false;
}
void AudioClip::BuildDecodedPCMData() const {
m_decodedPCMData.clear();
if (m_pcmData.Empty() || m_bitsPerSample == 0) {
m_decodedPCMValid = true;
const_cast<AudioClip*>(this)->RefreshMemorySize();
return;
}
const Core::uint32 bytesPerSample = m_bitsPerSample / 8u;
if (bytesPerSample == 0) {
m_decodedPCMValid = true;
const_cast<AudioClip*>(this)->RefreshMemorySize();
return;
}
const size_t totalSamples = m_pcmData.Size() / bytesPerSample;
m_decodedPCMData.resize(totalSamples, 0.0f);
const Core::uint8* rawData = m_pcmData.Data();
if (m_bitsPerSample == 8) {
for (size_t i = 0; i < totalSamples; ++i) {
m_decodedPCMData[i] = (static_cast<int>(rawData[i]) - 128) / 128.0f;
}
} else if (m_bitsPerSample == 16) {
const int16_t* samples16 = reinterpret_cast<const int16_t*>(rawData);
for (size_t i = 0; i < totalSamples; ++i) {
m_decodedPCMData[i] = samples16[i] / 32768.0f;
}
} else if (m_bitsPerSample == 24) {
for (size_t i = 0; i < totalSamples; ++i) {
int32_t sample =
(static_cast<int32_t>(rawData[i * 3]) |
(static_cast<int32_t>(rawData[i * 3 + 1]) << 8) |
(static_cast<int32_t>(rawData[i * 3 + 2]) << 16));
if ((sample & 0x00800000) != 0) {
sample |= static_cast<int32_t>(0xFF000000);
}
m_decodedPCMData[i] = sample / 8388608.0f;
}
} else if (m_bitsPerSample == 32) {
const int32_t* samples32 = reinterpret_cast<const int32_t*>(rawData);
for (size_t i = 0; i < totalSamples; ++i) {
m_decodedPCMData[i] = samples32[i] / 2147483648.0f;
}
} else {
m_decodedPCMData.clear();
}
m_decodedPCMValid = true;
const_cast<AudioClip*>(this)->RefreshMemorySize();
}
Core::uint64 AudioClip::GetFrameCount() const {
if (m_channels == 0 || m_bitsPerSample == 0) {
return 0;
}
const Core::uint64 bytesPerFrame =
static_cast<Core::uint64>(m_channels) * (static_cast<Core::uint64>(m_bitsPerSample) / 8u);
if (bytesPerFrame == 0) {
return 0;
}
return static_cast<Core::uint64>(m_pcmData.Size()) / bytesPerFrame;
}
Core::uint64 AudioClip::GetSampleCount() const {
return GetFrameCount() * static_cast<Core::uint64>(m_channels);
}
void AudioClip::SetRHIResource(class IRHIAudioBuffer* resource) {