audio: share decoded clip cache across sources
This commit is contained in:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user