Files
UnrealEngineUWP/Engine/Source/Runtime/Linux/ALAudio/Private/ALAudioBuffer.cpp
Dmitry Rekman b812cdd860 Fixing editor compilation issues (shadowing and etc).
#codereview Marc.Audy, Mike.Fricker
#lockdown Zachary.EdgertonJones

[CL 2522019 by Dmitry Rekman in Main branch]
2015-04-22 18:48:15 -04:00

210 lines
5.8 KiB
C++

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#include "ALAudioDevice.h"
#include "AudioEffect.h"
#include "Engine.h"
#include "IAudioFormat.h"
#include "AudioDecompress.h"
#include "ContentStreaming.h"
/*------------------------------------------------------------------------------------
FALSoundBuffer.
------------------------------------------------------------------------------------*/
/**
* Constructor
*
* @param AudioDevice audio device this sound buffer is going to be attached to.
*/
FALSoundBuffer::FALSoundBuffer( FALAudioDevice* InAudioDevice )
: FSoundBuffer(InAudioDevice)
{
}
/**
* Destructor
*
* Frees wave data and detaches itself from audio device.
*/
FALSoundBuffer::~FALSoundBuffer( void )
{
// Delete AL buffers.
alDeleteBuffers(1, &BufferId);
}
/**
* Static function used to create a buffer.
*
* @param InWave USoundNodeWave to use as template and wave source
* @param AudioDevice audio device to attach created buffer to
* @param bIsPrecacheRequest Whether this request is for precaching or not
* @return FALSoundBuffer pointer if buffer creation succeeded, NULL otherwise
*/
FALSoundBuffer* FALSoundBuffer::Init(FALAudioDevice* AudioDevice, USoundWave* InWave)
{
// Can't create a buffer without any source data
if (InWave == nullptr || InWave->NumChannels == 0)
{
return nullptr;
}
FAudioDeviceManager* AudioDeviceManager = GEngine->GetAudioDeviceManager();
check(AudioDeviceManager != nullptr);
FALSoundBuffer *Buffer = nullptr;
switch (static_cast<EDecompressionType>(InWave->DecompressionType))
{
case DTYPE_Setup:
// Has circumvented pre-cache mechanism - pre-cache now
AudioDevice->Precache(InWave, true, false);
// Recall this function with new decompression type
return Init(AudioDevice, InWave);
case DTYPE_Native:
if (InWave->ResourceID)
{
Buffer = static_cast<FALSoundBuffer*>(AudioDeviceManager->WaveBufferMap.FindRef(InWave->ResourceID));
}
if (!Buffer)
{
Buffer = CreateNativeBuffer(AudioDevice, InWave);
}
break;
// Always create a new buffer for streaming ogg vorbis data
//Buffer = CreateQueuedBuffer(AudioDevice, InWave);
//break;
case DTYPE_Invalid:
case DTYPE_Preview:
case DTYPE_Procedural:
case DTYPE_RealTime:
default:
// Invalid will be set if the wave cannot be played
UE_LOG(LogALAudio, Warning, TEXT("ALSoundBuffer wave '%s' has an invalid decompression type %d."),
*InWave->GetName(), static_cast<EDecompressionType>(InWave->DecompressionType));
break;
}
if (Buffer == nullptr)
{
UE_LOG(LogALAudio, Warning, TEXT("ALSoundBuffer init failed for wave '%s', decompression type %d."),
*InWave->GetName(), static_cast<EDecompressionType>(InWave->DecompressionType));
}
return Buffer;
}
FALSoundBuffer* FALSoundBuffer::CreateNativeBuffer( FALAudioDevice* AudioDevice, USoundWave* Wave)
{
SCOPE_CYCLE_COUNTER( STAT_AudioResourceCreationTime );
// Check to see if thread has finished decompressing on the other thread
if (Wave->AudioDecompressor)
{
Wave->AudioDecompressor->EnsureCompletion();
// Remove the decompressor
delete Wave->AudioDecompressor;
Wave->AudioDecompressor = nullptr;
}
// Can't create a buffer without any source data
if (Wave == nullptr)
{
return nullptr;
}
if (Wave->NumChannels == 0)
{
UE_LOG(LogALAudio, Warning, TEXT("ALSoundBuffer: cannot create buffer for wave '%s' with 0 channels"),
*Wave->GetName());
return nullptr;
}
Wave->InitAudioResource(AudioDevice->GetRuntimeFormat(Wave));
FALSoundBuffer* Buffer = nullptr;
FAudioDeviceManager* AudioDeviceManager = GEngine->GetAudioDeviceManager();
check(AudioDeviceManager != nullptr);
// Find the existing buffer if any
if (Wave->ResourceID)
{
Buffer = static_cast<FALSoundBuffer*>(AudioDeviceManager->WaveBufferMap.FindRef(Wave->ResourceID));
}
if (Buffer == nullptr)
{
// Create new buffer.
Buffer = new FALSoundBuffer(AudioDevice);
alGenBuffers(1, &Buffer->BufferId);
AudioDevice->alError(TEXT("RegisterSound"));
AudioDeviceManager->TrackResource(Wave, Buffer);
Buffer->InternalFormat = AudioDevice->GetInternalFormat(Wave->NumChannels);
Buffer->NumChannels = Wave->NumChannels;
Buffer->SampleRate = Wave->SampleRate;
if (Wave->RawPCMData)
{
// upload it
Buffer->BufferSize = Wave->RawPCMDataSize;
alBufferData(Buffer->BufferId, Buffer->InternalFormat, Wave->RawPCMData, Wave->RawPCMDataSize, Buffer->SampleRate);
// Free up the data if necessary
if (Wave->bDynamicResource)
{
FMemory::Free( Wave->RawPCMData );
Wave->RawPCMData = nullptr;
Wave->bDynamicResource = false;
}
}
else
{
// get the raw data
uint8* SoundData = reinterpret_cast<uint8*>(Wave->RawData.Lock(LOCK_READ_ONLY));
// it's (possibly) a pointer to a wave file, so skip over the header
int SoundDataSize = Wave->RawData.GetBulkDataSize();
// is there a wave header?
FWaveModInfo WaveInfo;
if (WaveInfo.ReadWaveInfo(SoundData, SoundDataSize))
{
// if so, modify the location and size of the sound data based on header
SoundData = WaveInfo.SampleDataStart;
SoundDataSize = WaveInfo.SampleDataSize;
}
// let the Buffer know the final size
Buffer->BufferSize = SoundDataSize;
// upload it
alBufferData( Buffer->BufferId, Buffer->InternalFormat, SoundData, Buffer->BufferSize, Buffer->SampleRate );
// unload it
Wave->RawData.Unlock();
}
if (AudioDevice->alError(TEXT( "RegisterSound (buffer data)")) || (Buffer->BufferSize == 0))
{
Buffer->InternalFormat = 0;
}
if (Buffer->InternalFormat == 0)
{
UE_LOG(LogAudio, Log,TEXT( "Audio: sound format not supported for '%s' (%d)" ), *Wave->GetName(), Wave->NumChannels);
UE_LOG(LogALAudio, Warning, TEXT("ALSoundBuffer: sound format not supported for wave '%s'"),
*Wave->GetName());
delete Buffer;
Buffer = nullptr;
}
}
return Buffer;
}