Unreal音频录制流程分析
先看一下录音数据的存储结构
/************************************************************************/
/* FAudioRecordingData */
/* This is used by USoundSubmix and the AudioMixerBlueprintLibrary */
/* to contain FSoundWavePCMWriter operations. */
/************************************************************************/
struct FAudioRecordingData
{
TSampleBuffer<int16> InputBuffer;
FSoundWavePCMWriter Writer;
~FAudioRecordingData() {};
};
其中,TSampleBuffer结构如下
template <class SampleType = DefaultUSoundWaveSampleType>
class TSampleBuffer
{
private:
// raw PCM data buffer
TArray<SampleType> RawPCMData;
// The number of samples in the buffer
int32 NumSamples;
// The number of frames in the buffer
int32 NumFrames;
// The number of channels in the buffer
int32 NumChannels;
// The sample rate of the buffer
int32 SampleRate;
// The duration of the buffer in seconds
float SampleDuration;
}
录制音频的关键函数
USoundWave* UAudioMixerBlueprintLibrary::StopRecordingOutput(const UObject* WorldContextObject, EAudioRecordingExportType ExportType, const FString& Name, FString Path, USoundSubmix* SubmixToRecord, USoundWave* ExistingSoundWaveToOverwrite)
{
if (RecordingData.IsValid())
{
UE_LOG(LogAudioMixer, Warning, TEXT("Abandoning existing write operation. If you'd like to export multiple submix recordings at the same time, use Start/Finish Recording Submix Output instead."));
}
if (Audio::FMixerDevice* MixerDevice = FAudioDeviceManager::GetAudioMixerDeviceFromWorldContext(WorldContextObject))
{
float SampleRate;
float ChannelCount;
// call the thing here.
Audio::FAlignedFloatBuffer& RecordedBuffer = MixerDevice->StopRecording(SubmixToRecord, ChannelCount, SampleRate);
if (RecordedBuffer.Num() == 0)
{
UE_LOG(LogAudioMixer, Warning, TEXT("No audio data. Did you call Start Recording Output?"));
return nullptr;
}
// Pack output data into a TSampleBuffer and record out:
RecordingData.Reset(new Audio::FAudioRecordingData());
RecordingData->InputBuffer = Audio::TSampleBuffer<int16>(RecordedBuffer, ChannelCount, SampleRate);
switch (ExportType)
{
case EAudioRecordingExportType::SoundWave:
{
USoundWave* ResultingSoundWave = RecordingData->Writer.SynchronouslyWriteSoundWave(RecordingData->InputBuffer, &Name, &Path);
RecordingData.Reset();
return ResultingSoundWave;
break;
}
case EAudioRecordingExportType::WavFile:
{
RecordingData->Writer.BeginWriteToWavFile(RecordingData->InputBuffer, Name, Path, [SubmixToRecord]()
{
if (SubmixToRecord && SubmixToRecord->OnSubmixRecordedFileDone.IsBound())
{
SubmixToRecord->OnSubmixRecordedFileDone.Broadcast(nullptr);
}
// I'm gonna try this, but I do not feel great about it.
RecordingData.Reset();
});
break;
}
default:
break;
}
}
else
{
UE_LOG(LogAudioMixer, Error, TEXT("Output recording is an audio mixer only feature."));
}
return nullptr;
}
认真写好每一行代码