225 lines
5.6 KiB
C++
225 lines
5.6 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "Containers/Queue.h"
|
|
#include "Sound/SoundWaveProcedural.h"
|
|
#include "Sound/SoundGenerator.h"
|
|
#include "AudioDecompress.h"
|
|
#include "AudioMixerBuffer.h"
|
|
|
|
class USoundWave;
|
|
|
|
namespace Audio
|
|
{
|
|
class FMixerBuffer;
|
|
class FMixerSourceBuffer;
|
|
|
|
// Data needed for a procedural audio task
|
|
struct FProceduralAudioTaskData
|
|
{
|
|
// The source which owns this decoding task
|
|
FMixerSourceBuffer* SourceBuffer;
|
|
|
|
// The sound generator to use to generate audio
|
|
ISoundGeneratorPtr SoundGenerator;
|
|
|
|
// The audio buffer to fill from the results of the generation
|
|
float* AudioData;
|
|
|
|
// The size of the audio buffer
|
|
int32 NumSamples;
|
|
|
|
// Force decodes to execute synchronously
|
|
bool bForceSyncDecode;
|
|
|
|
FProceduralAudioTaskData()
|
|
: SourceBuffer(nullptr)
|
|
, AudioData(nullptr)
|
|
, NumSamples(0)
|
|
, bForceSyncDecode(false)
|
|
{}
|
|
};
|
|
|
|
// Data needed for a decode audio task
|
|
struct FDecodeAudioTaskData
|
|
{
|
|
// A pointer to a buffer of audio which will be decoded to
|
|
float* AudioData;
|
|
|
|
// Decompression state for decoder
|
|
ICompressedAudioInfo* DecompressionState;
|
|
|
|
// The buffer type for the decoder
|
|
Audio::EBufferType::Type BufferType;
|
|
|
|
// Number of channels of the decoder
|
|
int32 NumChannels;
|
|
|
|
// The number of frames which are precached
|
|
int32 NumPrecacheFrames;
|
|
|
|
// The number of frames to decode
|
|
int32 NumFramesToDecode;
|
|
|
|
// Whether or not this sound is intending to be looped
|
|
bool bLoopingMode;
|
|
|
|
// Whether or not to skip the first buffer
|
|
bool bSkipFirstBuffer;
|
|
|
|
// Force this decoding operation to occur synchronously,
|
|
// regardless of the value of au.ForceSyncAudioDecodes. (used by time synth)
|
|
bool bForceSyncDecode;
|
|
|
|
FDecodeAudioTaskData()
|
|
: AudioData(nullptr)
|
|
, DecompressionState(nullptr)
|
|
, BufferType(Audio::EBufferType::Invalid)
|
|
, NumChannels(0)
|
|
, NumPrecacheFrames(0)
|
|
, NumFramesToDecode(0)
|
|
, bLoopingMode(false)
|
|
, bSkipFirstBuffer(false)
|
|
, bForceSyncDecode(false)
|
|
{}
|
|
};
|
|
|
|
// Data needed for a header parse audio task
|
|
struct FHeaderParseAudioTaskData
|
|
{
|
|
// The mixer buffer object which results will be written to
|
|
FMixerBuffer* MixerBuffer;
|
|
|
|
// The sound wave object which contains the encoded file
|
|
USoundWave* SoundWave;
|
|
|
|
FHeaderParseAudioTaskData()
|
|
: MixerBuffer(nullptr)
|
|
, SoundWave(nullptr)
|
|
{}
|
|
};
|
|
|
|
// Results from procedural audio task
|
|
struct FProceduralAudioTaskResults
|
|
{
|
|
int32 NumSamplesWritten;
|
|
bool bIsFinished;
|
|
float RelativeRenderCost = 1.f;
|
|
|
|
#if ENABLE_AUDIO_DEBUG
|
|
double CPUDuration = 0.0;
|
|
#endif // if ENABLE_AUDIO_DEBUG
|
|
|
|
FProceduralAudioTaskResults()
|
|
: NumSamplesWritten(0)
|
|
, bIsFinished(false)
|
|
{}
|
|
};
|
|
|
|
// Results from decode audio task
|
|
struct FDecodeAudioTaskResults
|
|
{
|
|
|
|
// Whether or not the audio buffer looped
|
|
bool bIsFinishedOrLooped;
|
|
int32 NumSamplesWritten = 0;
|
|
|
|
#if ENABLE_AUDIO_DEBUG
|
|
double CPUDuration = 0;
|
|
#endif // if ENABLE_AUDIO_DEBUG
|
|
|
|
FDecodeAudioTaskResults()
|
|
: bIsFinishedOrLooped(false)
|
|
{}
|
|
};
|
|
|
|
// The types of audio tasks
|
|
enum class EAudioTaskType
|
|
{
|
|
// The job is a procedural sound wave job to generate more audio
|
|
Procedural,
|
|
|
|
// The job is a header decode job
|
|
Header,
|
|
|
|
// The job is a decode job
|
|
Decode,
|
|
|
|
// The job is invalid (or unknown)
|
|
Invalid,
|
|
};
|
|
|
|
// Handle to an in-flight decode job. Can be queried and used on any thread.
|
|
class IAudioTask
|
|
{
|
|
public:
|
|
virtual ~IAudioTask() {}
|
|
|
|
// Queries if the decode job has finished.
|
|
virtual bool IsDone() const = 0;
|
|
|
|
// Returns the job type of the handle.
|
|
virtual EAudioTaskType GetType() const = 0;
|
|
|
|
// Ensures the completion of the decode operation.
|
|
virtual void EnsureCompletion() = 0;
|
|
|
|
// Cancel the decode operation
|
|
virtual void CancelTask() = 0;
|
|
|
|
// Returns the result of a procedural sound generate job
|
|
virtual void GetResult(FProceduralAudioTaskResults& OutResult) {};
|
|
|
|
// Returns the result of a decode job
|
|
virtual void GetResult(FDecodeAudioTaskResults& OutResult) {};
|
|
};
|
|
|
|
// Creates a task to decode a decoded file header
|
|
IAudioTask* CreateAudioTask(Audio::FDeviceId InDeviceId, const FHeaderParseAudioTaskData& InJobData);
|
|
|
|
// Creates a task for a procedural sound wave generation
|
|
IAudioTask* CreateAudioTask(Audio::FDeviceId InDeviceId, const FProceduralAudioTaskData& InJobData);
|
|
|
|
// Creates a task to decode a chunk of audio
|
|
IAudioTask* CreateAudioTask(Audio::FDeviceId InDeviceId, const FDecodeAudioTaskData& InJobData);
|
|
|
|
#if ENABLE_AUDIO_DEBUG
|
|
struct FScopeDecodeTimer
|
|
{
|
|
FScopeDecodeTimer(double* OutResultSeconds)
|
|
: Result(OutResultSeconds)
|
|
{
|
|
StartCycle = FPlatformTime::Cycles64();
|
|
}
|
|
~FScopeDecodeTimer()
|
|
{
|
|
uint64 EndCycle = FPlatformTime::Cycles64();
|
|
if (Result)
|
|
{
|
|
*Result = static_cast<double>(EndCycle - StartCycle) * FPlatformTime::GetSecondsPerCycle64();
|
|
}
|
|
}
|
|
|
|
double* Result = nullptr;
|
|
uint64 StartCycle = 0;
|
|
};
|
|
#endif // if ENABLE_AUDIO_DEBUG
|
|
|
|
// Creates a queue for audio decode requests with a specific Id. Tasks
|
|
// created with this Id will not be started immediately upon creation,
|
|
// but will instead be queued up to await a start "kick" later. NOTE:
|
|
// "kicking" the queue is the responsibility of the system that creates
|
|
// the queue, typically someplace like in a FOnAudioDevicePostRender delegate!
|
|
void CreateSynchronizedAudioTaskQueue(AudioTaskQueueId QueueId);
|
|
|
|
// Destroys an audio decode task queue. Tasks currently queued up are
|
|
// optionally started.
|
|
void DestroySynchronizedAudioTaskQueue(AudioTaskQueueId QueueId, bool RunCurrentQueue = false);
|
|
|
|
// "Kicks" all of the audio decode tasks currentlyt in the specified queue.
|
|
int KickQueuedTasks(AudioTaskQueueId QueueId);
|
|
|
|
}
|