Files
UnrealEngine/Engine/Source/Runtime/IOS/IOSAudio/Private/IOSAudioBuffer.cpp
2025-05-18 13:04:45 +08:00

205 lines
5.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
IOSAudioBuffer.cpp: Unreal IOSAudio buffer interface object.
=============================================================================*/
/*------------------------------------------------------------------------------------
Includes
------------------------------------------------------------------------------------*/
#include "IOSAudioDevice.h"
#include "AudioEffect.h"
#include "Interfaces/IAudioFormat.h"
#include "Sound/SoundWave.h"
#include "AudioDeviceManager.h"
#include "Engine/Engine.h"
#include "AudioDecompress.h"
/*------------------------------------------------------------------------------------
FIOSAudioSoundBuffer
------------------------------------------------------------------------------------*/
FIOSAudioSoundBuffer::FIOSAudioSoundBuffer(FIOSAudioDevice* InAudioDevice, USoundWave* InWave, bool InStreaming, bool InProcedural):
FSoundBuffer(InAudioDevice),
SampleData(nullptr),
BufferSize(0),
DecompressionState(nullptr),
bStreaming(InStreaming),
bIsProcedural(InProcedural)
{
if (!bIsProcedural)
{
if (!ReadCompressedInfo(InWave))
{
return;
}
SoundFormat = SoundFormat_LPCM;
}
else
{
SoundFormat = SoundFormat_LPCM;
}
SampleRate = InWave->GetSampleRateForCurrentPlatform();
NumChannels = InWave->NumChannels;
BufferSize = AudioCallbackFrameSize * sizeof(uint16) * NumChannels;
SampleData = static_cast<int16*>(FMemory::Malloc(BufferSize));
check(SampleData != nullptr);
FMemory::Memzero(SampleData, BufferSize);
FAudioDeviceManager* AudioDeviceManager = GEngine->GetAudioDeviceManager();
check(AudioDeviceManager != nullptr);
// There is no need to track this resource with the AudioDeviceManager since there is a one to one mapping between FIOSAudioSoundBuffer objects and FIOSAudioSoundSource objects
// and this object will be deleted when the corresponding FIOSAudioSoundSource no longer needs it
}
FIOSAudioSoundBuffer::~FIOSAudioSoundBuffer(void)
{
if (bAllocationInPermanentPool)
{
UE_LOG(LogIOSAudio, Fatal, TEXT("Can't free resource '%s' as it was allocated in permanent pool."), *ResourceName);
}
if(SampleData != nullptr)
{
FMemory::Free(SampleData);
SampleData = nullptr;
}
if(DecompressionState != nullptr)
{
delete DecompressionState;
DecompressionState = nullptr;
}
}
int32 FIOSAudioSoundBuffer::GetSize(void)
{
int32 TotalSize = 0;
switch (SoundFormat)
{
case SoundFormat_LPCM:
case SoundFormat_ADPCM:
TotalSize = BufferSize;
break;
}
return TotalSize;
}
int32 FIOSAudioSoundBuffer::GetCurrentChunkIndex() const
{
if(DecompressionState == nullptr)
{
return -1;
}
return DecompressionState->GetCurrentChunkIndex();
}
int32 FIOSAudioSoundBuffer::GetCurrentChunkOffset() const
{
if(DecompressionState == nullptr)
{
return -1;
}
return DecompressionState->GetCurrentChunkOffset();
}
bool FIOSAudioSoundBuffer::ReadCompressedInfo(USoundWave* InWave)
{
check(DecompressionState != nullptr);
FSoundQualityInfo QualityInfo = { 0 };
if(bStreaming)
{
return DecompressionState->StreamCompressedInfo(InWave, &QualityInfo);
}
InWave->InitAudioResource(FName(TEXT("ADPCM")));
if (InWave->GetResourceSize() <= 0)
{
InWave->RemoveAudioResource();
return false;
}
return DecompressionState->ReadCompressedInfo(InWave->GetResourceData(), InWave->GetResourceSize(), &QualityInfo);
}
bool FIOSAudioSoundBuffer::ReadCompressedData( uint8* Destination, int32 NumFramesToDecode, bool bLooping )
{
int32 NumFramesDecoded = NumFramesToDecode;
if(bStreaming)
{
return DecompressionState->StreamCompressedData(Destination, bLooping, RenderCallbackBufferSize, NumFramesDecoded);
}
else
{
return DecompressionState->ReadCompressedData(Destination, bLooping, RenderCallbackBufferSize);
}
}
FIOSAudioSoundBuffer* FIOSAudioSoundBuffer::Init(FIOSAudioDevice* IOSAudioDevice, USoundWave* InWave)
{
// Can't create a buffer without any source data
if (InWave == NULL || InWave->NumChannels == 0)
{
return NULL;
}
FAudioDeviceManager* AudioDeviceManager = GEngine->GetAudioDeviceManager();
FIOSAudioSoundBuffer *Buffer = NULL;
bool bIsStreaming = false;
switch (static_cast<EDecompressionType>(InWave->DecompressionType))
{
case DTYPE_Setup:
// Has circumvented pre-cache mechanism - pre-cache now
IOSAudioDevice->Precache(InWave, true, false);
// Recall this function with new decompression type
return Init(IOSAudioDevice, InWave);
case DTYPE_Streaming:
bIsStreaming = true;
// fall through to next case
case DTYPE_RealTime:
// Always create a new FIOSAudioSoundBuffer since positional information about the sound is kept track of in this object
Buffer = new FIOSAudioSoundBuffer(IOSAudioDevice, InWave, bIsStreaming, false);
break;
case DTYPE_Procedural:
Buffer = new FIOSAudioSoundBuffer(IOSAudioDevice, InWave, bIsStreaming, true);
break;
case DTYPE_Invalid:
default:
// Invalid will be set if the wave cannot be played
UE_LOG( LogIOSAudio, Warning, TEXT("Init Buffer on unsupported sound type name = %s type = %d"), *InWave->GetName(), int32(InWave->DecompressionType));
break;
}
return Buffer;
}
bool FIOSAudioSoundBuffer::ReleaseCurrentChunk()
{
if (DecompressionState && bStreaming)
{
return DecompressionState->ReleaseStreamChunk(true);
}
else
{
return true;
}
}