You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Existing workloads should continue to work as they always have, but it is now possible for a procedural sound (SoundGenerator) to specify a "synchronized render queue" that its "audio decode tasks" should be added to. That queue's jobs are then held for the duration of the OnProcessAudioStream function and only kicked when some "owning" system kicks the queued tasks. In the Harmonix Music specific case, UMusicEmitterComponent (a subclass of a USynthComponent) creates soundgenerators that specify a unique render queue id. Then, in the Harmonix Music system's "post render callback" which is called at the bottom of the FMixerDevice::OnProcessAudioStream, after doing the synchrnous "state updates" for all of the music renderers to keep them in sync, we kick all the queued up tasks so async rendering can proceed. [REVIEW] [at]aaron.mcleran [at]phil.popp [at]rob.gay [at]jimmy.smith #preflight 6216c0c7db60b6b592017336 #ROBOMERGE-AUTHOR: buzz.burrowes #ROBOMERGE-SOURCE: CL 19107053 via CL 19116514 via CL 19116561 via CL 19116594 via CL 19117383 #ROBOMERGE-BOT: UE5 (Release-Engine-Staging -> Main) (v921-19075845) [CL 19153372 by buzz burrowes in ue5-main branch]
196 lines
5.1 KiB
C++
196 lines
5.1 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;
|
|
|
|
// Data needed for a procedural audio task
|
|
struct FProceduralAudioTaskData
|
|
{
|
|
// The procedural sound wave ptr to use to generate audio with
|
|
// TODO: remove the need for this
|
|
USoundWave* ProceduralSoundWave;
|
|
|
|
// 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;
|
|
|
|
// The number of channels of the procedural buffer
|
|
int32 NumChannels;
|
|
|
|
// Force decodes to execute synchronously
|
|
bool bForceSyncDecode;
|
|
|
|
FProceduralAudioTaskData()
|
|
: ProceduralSoundWave(nullptr)
|
|
, AudioData(nullptr)
|
|
, NumSamples(0)
|
|
, NumChannels(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;
|
|
|
|
FProceduralAudioTaskResults()
|
|
: NumSamplesWritten(0)
|
|
, bIsFinished(false)
|
|
{}
|
|
};
|
|
|
|
// Results from decode audio task
|
|
struct FDecodeAudioTaskResults
|
|
{
|
|
// Whether or not the audio buffer looped
|
|
bool bIsFinishedOrLooped;
|
|
|
|
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);
|
|
|
|
// 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);
|
|
|
|
}
|