Encoding changes, UNIX/Mac optimising

This commit is contained in:
Georgy Treshchev
2021-02-19 10:08:21 +01:00
parent 23fd2c3238
commit c0943e2852
2 changed files with 270 additions and 191 deletions
@@ -5,7 +5,6 @@
URuntimeAudioImporterLibrary::URuntimeAudioImporterLibrary(const FObjectInitializer& ObjectInitializer) URuntimeAudioImporterLibrary::URuntimeAudioImporterLibrary(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer) : Super(ObjectInitializer)
{ {
} }
URuntimeAudioImporterLibrary* URuntimeAudioImporterLibrary::CreateRuntimeAudioImporter() URuntimeAudioImporterLibrary* URuntimeAudioImporterLibrary::CreateRuntimeAudioImporter()
@@ -15,18 +14,20 @@ URuntimeAudioImporterLibrary* URuntimeAudioImporterLibrary::CreateRuntimeAudioIm
return Importer; return Importer;
} }
URuntimeAudioImporterLibrary* URuntimeAudioImporterLibrary::ImportAudioFromFile(const FString& filePath, TEnumAsByte < AudioFormat > Format, bool DefineFormatAutomatically) URuntimeAudioImporterLibrary* URuntimeAudioImporterLibrary::ImportAudioFromFile(
const FString& FilePath, TEnumAsByte<AudioFormat> Format, bool DefineFormatAutomatically)
{ {
AsyncTask(ENamedThreads::AnyThread, [=]() { AsyncTask(ENamedThreads::AnyThread, [=]()
GetUSoundWaveFromAudioFile_Internal(filePath, Format, DefineFormatAutomatically); {
GetUSoundWaveFromAudioFile_Internal(FilePath, Format, DefineFormatAutomatically);
}); });
return this; return this;
} }
bool URuntimeAudioImporterLibrary::DestroySoundWave(USoundWave* ReadySoundWave) { bool URuntimeAudioImporterLibrary::DestroySoundWave(USoundWave* ReadySoundWave)
{
if (ReadySoundWave->IsValidLowLevel()) { if (ReadySoundWave->IsValidLowLevel())
{
//Begin USoundWave destroy (block changing some data) //Begin USoundWave destroy (block changing some data)
ReadySoundWave->ConditionalBeginDestroy(); ReadySoundWave->ConditionalBeginDestroy();
ReadySoundWave->BeginDestroy(); ReadySoundWave->BeginDestroy();
@@ -34,7 +35,8 @@ bool URuntimeAudioImporterLibrary::DestroySoundWave(USoundWave* ReadySoundWave)
//Delete all audio data from physical memory //Delete all audio data from physical memory
ReadySoundWave->RawData.RemoveBulkData(); ReadySoundWave->RawData.RemoveBulkData();
ReadySoundWave->RemoveAudioResource(); ReadySoundWave->RemoveAudioResource();
AsyncTask(ENamedThreads::AudioThread, [=]() { AsyncTask(ENamedThreads::AudioThread, [=]()
{
ReadySoundWave->InvalidateCompressedData(true); ReadySoundWave->InvalidateCompressedData(true);
}); });
@@ -44,7 +46,8 @@ bool URuntimeAudioImporterLibrary::DestroySoundWave(USoundWave* ReadySoundWave)
ReadySoundWave->FinishDestroy(); ReadySoundWave->FinishDestroy();
return true; return true;
} }
else { else
{
return false; return false;
} }
} }
@@ -63,10 +66,12 @@ void* unreal_malloc(size_t sz, void* pUserData)
{ {
return FMemory::Malloc(sz); return FMemory::Malloc(sz);
} }
void* unreal_realloc(void* p, size_t sz, void* pUserData) void* unreal_realloc(void* p, size_t sz, void* pUserData)
{ {
return FMemory::Realloc(p, sz); return FMemory::Realloc(p, sz);
} }
void unreal_free(void* p, void* pUserData) void unreal_free(void* p, void* pUserData)
{ {
FMemory::Free(p); FMemory::Free(p);
@@ -77,9 +82,6 @@ bool URuntimeAudioImporterLibrary::ExportSoundWaveToFile(USoundWave* SoundWaveTo
uint8* PCMData = SoundWaveToExport->RawPCMData; uint8* PCMData = SoundWaveToExport->RawPCMData;
size_t PCMDataSize = SoundWaveToExport->RawPCMDataSize; size_t PCMDataSize = SoundWaveToExport->RawPCMDataSize;
uint32 SampleRate;
uint16 ChannelCount;
drwav_allocation_callbacks allocationCallbacksDecoding; drwav_allocation_callbacks allocationCallbacksDecoding;
allocationCallbacksDecoding.pUserData = NULL; allocationCallbacksDecoding.pUserData = NULL;
allocationCallbacksDecoding.onMalloc = unreal_malloc; allocationCallbacksDecoding.onMalloc = unreal_malloc;
@@ -88,8 +90,9 @@ bool URuntimeAudioImporterLibrary::ExportSoundWaveToFile(USoundWave* SoundWaveTo
drwav_uint64 framesToWrite = PCMDataSize / sizeof(DR_WAVE_FORMAT_PCM) / SoundWaveToExport->NumChannels; drwav_uint64 framesToWrite = PCMDataSize / sizeof(DR_WAVE_FORMAT_PCM) / SoundWaveToExport->NumChannels;
ChannelCount = SoundWaveToExport->NumChannels; uint16 ChannelCount = SoundWaveToExport->NumChannels;
SampleRate = FGenericPlatformMath::RoundToInt((framesToWrite / (float)SoundWaveToExport->GetDuration() * ChannelCount)); uint32 SampleRate = FGenericPlatformMath::RoundToInt(
(framesToWrite / (float)SoundWaveToExport->GetDuration() * ChannelCount));
drwav wavEncode; drwav wavEncode;
@@ -100,7 +103,14 @@ bool URuntimeAudioImporterLibrary::ExportSoundWaveToFile(USoundWave* SoundWaveTo
format.sampleRate = SampleRate; format.sampleRate = SampleRate;
format.bitsPerSample = 16; format.bitsPerSample = 16;
if (!drwav_init_file_write_w(&wavEncode, (wchar_t*)PathToExport.GetCharArray().GetData(), &format, &allocationCallbacksDecoding)) { #if PLATFORM_WINDOWS
if (!drwav_init_file_write_w(&wavEncode, (wchar_t*)PathToExport.GetCharArray().GetData(), &format,
&allocationCallbacksDecoding))
#else
if (!drwav_init_file_write(&wavEncode, TCHAR_TO_UTF8(*PathToExport), &format,
&allocationCallbacksDecoding))
#endif
{
return false; return false;
} }
@@ -110,48 +120,61 @@ bool URuntimeAudioImporterLibrary::ExportSoundWaveToFile(USoundWave* SoundWaveTo
return true; return true;
} }
URuntimeAudioImporterLibrary* URuntimeAudioImporterLibrary::GetUSoundWaveFromAudioFile_Internal(const FString& filePath, TEnumAsByte < AudioFormat > Format, bool DefineFormatAutomatically) URuntimeAudioImporterLibrary* URuntimeAudioImporterLibrary::GetUSoundWaveFromAudioFile_Internal(
const FString& FilePath, TEnumAsByte<AudioFormat> Format, bool DefineFormatAutomatically)
{ {
TEnumAsByte<TranscodingStatus> Status; TEnumAsByte<TranscodingStatus> Status;
if (FPaths::FileExists(filePath) != true) { if (FPaths::FileExists(FilePath) != true)
{
Status = TranscodingStatus::AudioDoesNotExist; Status = TranscodingStatus::AudioDoesNotExist;
// Callback Dispatcher OnResult // Callback Dispatcher OnResult
OnResult_Internal(nullptr, Status); OnResult_Internal(nullptr, Status);
} }
else { else
{
int16_t* pSampleData; int16_t* pSampleData;
uint64 framesToWrite; uint64 framesToWrite;
uint32 channels; uint32 channels;
uint32 sampleRate; uint32 sampleRate;
if (DefineFormatAutomatically) { if (DefineFormatAutomatically)
Format = GetAudioFormat(filePath); {
Format = GetAudioFormat(FilePath);
} }
if (Format == AudioFormat::INVALID) { if (Format == AudioFormat::INVALID)
{
Status = TranscodingStatus::InvalidAudioFormat; Status = TranscodingStatus::InvalidAudioFormat;
// Callback Dispatcher OnResult // Callback Dispatcher OnResult
OnResult_Internal(nullptr, Status); OnResult_Internal(nullptr, Status);
} }
else { else
if (TranscodeAudioFileToPCMData((wchar_t*)filePath.GetCharArray().GetData(), Format, Status, framesToWrite, pSampleData, channels, sampleRate) == false) { {
if (TranscodeAudioFileToPCMData(FilePath, Format, Status, framesToWrite, pSampleData, channels, sampleRate)
== false)
{
// Callback Dispatcher OnResult // Callback Dispatcher OnResult
OnResult_Internal(nullptr, Status); OnResult_Internal(nullptr, Status);
} }
else { else
{
void* WaveData; void* WaveData;
size_t WaveDataSize; size_t WaveDataSize;
if (TranscodePCMToWAVData(*&WaveData, *&WaveDataSize, framesToWrite, *&pSampleData, channels, sampleRate) == false) { if (TranscodePCMToWAVData(*&WaveData, *&WaveDataSize, framesToWrite, *&pSampleData, channels,
sampleRate) == false)
{
FMemory::Free(pSampleData); FMemory::Free(pSampleData);
// Callback Dispatcher OnResult // Callback Dispatcher OnResult
OnResult_Internal(nullptr, Status); OnResult_Internal(nullptr, Status);
} }
else { else
USoundWave* ReadyUSoundWave = GetSoundWaveObject((const uint8*)WaveData, WaveDataSize, Status); // A ready USoundWave static object {
USoundWave* ReadyUSoundWave = GetSoundWaveObject((const uint8*)WaveData, WaveDataSize, Status);
// A ready USoundWave static object
/* Free temporary transcoding data */ /* Free temporary transcoding data */
FMemory::Free(WaveData); FMemory::Free(WaveData);
@@ -164,18 +187,18 @@ URuntimeAudioImporterLibrary* URuntimeAudioImporterLibrary::GetUSoundWaveFromAud
// Callback Dispatcher OnResult // Callback Dispatcher OnResult
OnResult_Internal(ReadyUSoundWave, Status); OnResult_Internal(ReadyUSoundWave, Status);
} }
} }
} }
} }
return this; return this;
} }
class USoundWave* URuntimeAudioImporterLibrary::GetSoundWaveObject(const uint8* WaveData, int32 WaveDataSize, TEnumAsByte < TranscodingStatus >& Status) class USoundWave* URuntimeAudioImporterLibrary::GetSoundWaveObject(const uint8* WaveData, int32 WaveDataSize,
TEnumAsByte<TranscodingStatus>& Status)
{ {
USoundWave* sw = NewObject<USoundWave>(USoundWave::StaticClass()); USoundWave* sw = NewObject<USoundWave>(USoundWave::StaticClass());
if (!sw) { if (!sw)
{
Status = TranscodingStatus::USoundWaveDeclarationError; Status = TranscodingStatus::USoundWaveDeclarationError;
return nullptr; return nullptr;
} }
@@ -190,7 +213,8 @@ class USoundWave* URuntimeAudioImporterLibrary::GetSoundWaveObject(const uint8*
// Callback Dispatcher OnProgress (not completely accurate implementation) // Callback Dispatcher OnProgress (not completely accurate implementation)
OnProgress_Internal(75); OnProgress_Internal(75);
if (*WaveInfo.pBitsPerSample != 16) { if (*WaveInfo.pBitsPerSample != 16)
{
Status = TranscodingStatus::UnsupportedBitDepth; Status = TranscodingStatus::UnsupportedBitDepth;
return nullptr; return nullptr;
} }
@@ -222,17 +246,25 @@ class USoundWave* URuntimeAudioImporterLibrary::GetSoundWaveObject(const uint8*
// Callback Dispatcher OnProgress (not completely accurate implementation) // Callback Dispatcher OnProgress (not completely accurate implementation)
OnProgress_Internal(85); OnProgress_Internal(85);
} }
else { else
if (ErrorReason.Equals(TEXT("Invalid WAVE file."), ESearchCase::CaseSensitive)) { {
if (ErrorReason.Equals(TEXT("Invalid WAVE file."), ESearchCase::CaseSensitive))
{
Status = TranscodingStatus::InvalidWAVEData; Status = TranscodingStatus::InvalidWAVEData;
} }
else if (ErrorReason.Equals(TEXT("Unsupported WAVE file format: actual bit rate does not match the container size."), ESearchCase::CaseSensitive)) { else if (ErrorReason.Equals(
TEXT("Unsupported WAVE file format: actual bit rate does not match the container size."),
ESearchCase::CaseSensitive))
{
Status = TranscodingStatus::InvalidBitrate; Status = TranscodingStatus::InvalidBitrate;
} }
else if (ErrorReason.Equals(TEXT("Unsupported WAVE file format: subformat identifier not recognized."), ESearchCase::CaseSensitive)) { else if (ErrorReason.Equals(
TEXT("Unsupported WAVE file format: subformat identifier not recognized."), ESearchCase::CaseSensitive))
{
Status = TranscodingStatus::InvalidSubformat; Status = TranscodingStatus::InvalidSubformat;
} }
else { else
{
Status = TranscodingStatus::UnrecognizedReadWaveError; Status = TranscodingStatus::UnrecognizedReadWaveError;
} }
return nullptr; return nullptr;
@@ -248,7 +280,8 @@ class USoundWave* URuntimeAudioImporterLibrary::GetSoundWaveObject(const uint8*
// Callback Dispatcher OnProgress (not completely accurate implementation) // Callback Dispatcher OnProgress (not completely accurate implementation)
OnProgress_Internal(95); OnProgress_Internal(95);
if (!sw) { if (!sw)
{
Status = TranscodingStatus::InvalidUSoundWave; Status = TranscodingStatus::InvalidUSoundWave;
return nullptr; return nullptr;
} }
@@ -256,7 +289,10 @@ class USoundWave* URuntimeAudioImporterLibrary::GetSoundWaveObject(const uint8*
return sw; return sw;
} }
bool URuntimeAudioImporterLibrary::TranscodeAudioFileToPCMData(const wchar_t* filePath, TEnumAsByte < AudioFormat > Format, TEnumAsByte < TranscodingStatus >& Status, uint64& framesToWrite, int16_t*& pSampleData, uint32& channels, uint32& sampleRate) bool URuntimeAudioImporterLibrary::TranscodeAudioFileToPCMData(FString FilePath, TEnumAsByte<AudioFormat> Format,
TEnumAsByte<TranscodingStatus>& Status,
uint64& framesToWrite, int16_t*& pSampleData,
uint32& channels, uint32& sampleRate)
{ {
OnProgress_Internal(5); OnProgress_Internal(5);
switch (Format) switch (Format)
@@ -270,15 +306,22 @@ bool URuntimeAudioImporterLibrary::TranscodeAudioFileToPCMData(const wchar_t* fi
allocationCallbacksDecoding.onFree = unreal_free; allocationCallbacksDecoding.onFree = unreal_free;
drmp3 mp3; drmp3 mp3;
if (!drmp3_init_file_w(&mp3, filePath, &allocationCallbacksDecoding)) { #if PLATFORM_WINDOWS
if (!drmp3_init_file_w(&mp3, (wchar_t*)FilePath.GetCharArray().GetData(), &allocationCallbacksDecoding))
#else
if (!drmp3_init_file(&mp3, TCHAR_TO_UTF8(*FilePath), &allocationCallbacksDecoding))
#endif
{
Status = TranscodingStatus::FailedToOpenStream; Status = TranscodingStatus::FailedToOpenStream;
return false; return false;
} }
else { else
{
// Callback Dispatcher OnProgress (not completely accurate implementation) // Callback Dispatcher OnProgress (not completely accurate implementation)
OnProgress_Internal(10); OnProgress_Internal(10);
pSampleData = (int16_t*)FMemory::Malloc((size_t)drmp3_get_pcm_frame_count(&mp3) * mp3.channels * sizeof(int16_t)); pSampleData = (int16_t*)FMemory::Malloc(
(size_t)drmp3_get_pcm_frame_count(&mp3) * mp3.channels * sizeof(int16_t));
// Callback Dispatcher OnProgress (not completely accurate implementation) // Callback Dispatcher OnProgress (not completely accurate implementation)
OnProgress_Internal(15); OnProgress_Internal(15);
@@ -304,15 +347,22 @@ bool URuntimeAudioImporterLibrary::TranscodeAudioFileToPCMData(const wchar_t* fi
allocationCallbacksDecoding.onFree = unreal_free; allocationCallbacksDecoding.onFree = unreal_free;
drwav wav; drwav wav;
if (!drwav_init_file_w(&wav, filePath, &allocationCallbacksDecoding)) { #if PLATFORM_WINDOWS
if (!drwav_init_file_w(&wav, (wchar_t*)FilePath.GetCharArray().GetData(), &allocationCallbacksDecoding))
#else
if (!drwav_init_file(&wav, TCHAR_TO_UTF8(*FilePath), &allocationCallbacksDecoding))
#endif
{
Status = TranscodingStatus::FailedToOpenStream; Status = TranscodingStatus::FailedToOpenStream;
return false; return false;
} }
else { else
{
// Callback Dispatcher OnProgress (not completely accurate implementation) // Callback Dispatcher OnProgress (not completely accurate implementation)
OnProgress_Internal(10); OnProgress_Internal(10);
pSampleData = (int16_t*)FMemory::Malloc((size_t)wav.totalPCMFrameCount * wav.channels * sizeof(int16_t)); pSampleData = (int16_t*)
FMemory::Malloc((size_t)wav.totalPCMFrameCount * wav.channels * sizeof(int16_t));
// Callback Dispatcher OnProgress (not completely accurate implementation) // Callback Dispatcher OnProgress (not completely accurate implementation)
OnProgress_Internal(15); OnProgress_Internal(15);
@@ -337,16 +387,25 @@ bool URuntimeAudioImporterLibrary::TranscodeAudioFileToPCMData(const wchar_t* fi
allocationCallbacksDecoding.onRealloc = unreal_realloc; allocationCallbacksDecoding.onRealloc = unreal_realloc;
allocationCallbacksDecoding.onFree = unreal_free; allocationCallbacksDecoding.onFree = unreal_free;
drflac* pFlac = drflac_open_file_w(filePath, &allocationCallbacksDecoding); #if PLATFORM_WINDOWS
if (pFlac == NULL) { drflac* pFlac = drflac_open_file_w((wchar_t*)FilePath.GetCharArray().GetData(),
&allocationCallbacksDecoding);
#else
drflac* pFlac = drflac_open_file(TCHAR_TO_UTF8(*FilePath),
&allocationCallbacksDecoding);
#endif
if (pFlac == NULL)
{
Status = TranscodingStatus::FailedToOpenStream; Status = TranscodingStatus::FailedToOpenStream;
return false; return false;
} }
else { else
{
// Callback Dispatcher OnProgress (not completely accurate implementation) // Callback Dispatcher OnProgress (not completely accurate implementation)
OnProgress_Internal(10); OnProgress_Internal(10);
pSampleData = (int16_t*)FMemory::Malloc((size_t)pFlac->totalPCMFrameCount * pFlac->channels * sizeof(int16_t)); pSampleData = (int16_t*)FMemory::Malloc(
(size_t)pFlac->totalPCMFrameCount * pFlac->channels * sizeof(int16_t));
// Callback Dispatcher OnProgress (not completely accurate implementation) // Callback Dispatcher OnProgress (not completely accurate implementation)
OnProgress_Internal(15); OnProgress_Internal(15);
@@ -372,7 +431,9 @@ bool URuntimeAudioImporterLibrary::TranscodeAudioFileToPCMData(const wchar_t* fi
} }
} }
bool URuntimeAudioImporterLibrary::TranscodePCMToWAVData(void*& WaveData, size_t& WaveDataSize, uint64 framesToWrite, int16_t*& pSampleData, uint32 channels, uint32 sampleRate) { bool URuntimeAudioImporterLibrary::TranscodePCMToWAVData(void*& WaveData, size_t& WaveDataSize, uint64 framesToWrite,
int16_t*& pSampleData, uint32 channels, uint32 sampleRate)
{
drwav wavEncode; drwav wavEncode;
drwav_data_format format; drwav_data_format format;
format.container = drwav_container_riff; format.container = drwav_container_riff;
@@ -386,7 +447,8 @@ bool URuntimeAudioImporterLibrary::TranscodePCMToWAVData(void*& WaveData, size_t
allocationCallbacks.onMalloc = unreal_malloc; allocationCallbacks.onMalloc = unreal_malloc;
allocationCallbacks.onRealloc = unreal_realloc; allocationCallbacks.onRealloc = unreal_realloc;
allocationCallbacks.onFree = unreal_free; allocationCallbacks.onFree = unreal_free;
if (!drwav_init_memory_write(&wavEncode, &WaveData, &WaveDataSize, &format, &allocationCallbacks)) { if (!drwav_init_memory_write(&wavEncode, &WaveData, &WaveDataSize, &format, &allocationCallbacks))
{
return false; //error return false; //error
} }
@@ -404,30 +466,36 @@ bool URuntimeAudioImporterLibrary::TranscodePCMToWAVData(void*& WaveData, size_t
TEnumAsByte<AudioFormat> URuntimeAudioImporterLibrary::GetAudioFormat(const FString& filePath) TEnumAsByte<AudioFormat> URuntimeAudioImporterLibrary::GetAudioFormat(const FString& filePath)
{ {
if (FPaths::GetExtension(filePath, false).Equals(TEXT("mp3"), ESearchCase::IgnoreCase)) { if (FPaths::GetExtension(filePath, false).Equals(TEXT("mp3"), ESearchCase::IgnoreCase))
{
return AudioFormat::MP3; return AudioFormat::MP3;
} }
else if (FPaths::GetExtension(filePath, false).Equals(TEXT("wav"), ESearchCase::IgnoreCase)) { else if (FPaths::GetExtension(filePath, false).Equals(TEXT("wav"), ESearchCase::IgnoreCase))
{
return AudioFormat::WAV; return AudioFormat::WAV;
} }
else if (FPaths::GetExtension(filePath, false).Equals(TEXT("flac"), ESearchCase::IgnoreCase)) { else if (FPaths::GetExtension(filePath, false).Equals(TEXT("flac"), ESearchCase::IgnoreCase))
{
return AudioFormat::FLAC; return AudioFormat::FLAC;
} }
else { else
{
return AudioFormat::INVALID; return AudioFormat::INVALID;
} }
} }
void URuntimeAudioImporterLibrary::OnProgress_Internal(int32 Percentage) void URuntimeAudioImporterLibrary::OnProgress_Internal(int32 Percentage)
{ {
AsyncTask(ENamedThreads::GameThread, [=]() { AsyncTask(ENamedThreads::GameThread, [=]()
{
OnProgress.Broadcast(Percentage); OnProgress.Broadcast(Percentage);
}); });
} }
void URuntimeAudioImporterLibrary::OnResult_Internal(USoundWave* ReadySoundWave, TEnumAsByte<TranscodingStatus> Status) void URuntimeAudioImporterLibrary::OnResult_Internal(USoundWave* ReadySoundWave, TEnumAsByte<TranscodingStatus> Status)
{ {
AsyncTask(ENamedThreads::GameThread, [=]() { AsyncTask(ENamedThreads::GameThread, [=]()
{
RemoveFromRoot(); RemoveFromRoot();
OnResult.Broadcast(ReadySoundWave, Status); OnResult.Broadcast(ReadySoundWave, Status);
}); });
@@ -51,7 +51,8 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnProgress, const int32, Percentage
* @param ReadySoundWave Ready USoundWave Object * @param ReadySoundWave Ready USoundWave Object
* @param Status Reference to TranscodingStatus Enumerator in case an error occurs * @param Status Reference to TranscodingStatus Enumerator in case an error occurs
*/ */
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnResult, const USoundWave*, ReadySoundWave, const TEnumAsByte < TranscodingStatus >, Status); DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnResult, const USoundWave*, ReadySoundWave,
const TEnumAsByte < TranscodingStatus >, Status);
UCLASS(BlueprintType, Category = "RuntimeFilesDownloader") UCLASS(BlueprintType, Category = "RuntimeFilesDownloader")
class RUNTIMEAUDIOIMPORTER_API URuntimeAudioImporterLibrary : public UObject class RUNTIMEAUDIOIMPORTER_API URuntimeAudioImporterLibrary : public UObject
@@ -75,19 +76,22 @@ public:
* *
* @return The RuntimeAudioImporter object. Bind to it's OnProgress and OnResult events to know when it is in the process of transcoding and has been transcoded. * @return The RuntimeAudioImporter object. Bind to it's OnProgress and OnResult events to know when it is in the process of transcoding and has been transcoded.
*/ */
UFUNCTION(BlueprintCallable, meta = (Keywords = "Create, Audio, Runtime, MP3, FLAC, WAV"), Category = "RuntimeAudioImporter") UFUNCTION(BlueprintCallable, meta = (Keywords = "Create, Audio, Runtime, MP3, FLAC, WAV"), Category =
"RuntimeAudioImporter")
static URuntimeAudioImporterLibrary* CreateRuntimeAudioImporter(); static URuntimeAudioImporterLibrary* CreateRuntimeAudioImporter();
/** /**
* Transcode audio file to USoundWave static object * Transcode audio file to USoundWave static object
* *
* @param filePath Path to the audio file to import * @param FilePath Path to the audio file to import
* @param Format Audio file format (extension) * @param Format Audio file format (extension)
* @param DefineFormatAutomatically Whether to define format (extension) automatically or not * @param DefineFormatAutomatically Whether to define format (extension) automatically or not
* @return Returns itself. * @return Returns itself.
*/ */
UFUNCTION(BlueprintCallable, meta = (Keywords = "Importer, Transcoder, Converter, Runtime, MP3, FLAC, WAV"), Category = "RuntimeAudioImporter") UFUNCTION(BlueprintCallable, meta = (Keywords = "Importer, Transcoder, Converter, Runtime, MP3, FLAC, WAV"),
URuntimeAudioImporterLibrary * ImportAudioFromFile(const FString & filePath, TEnumAsByte < AudioFormat > Format, bool DefineFormatAutomatically); Category = "RuntimeAudioImporter")
URuntimeAudioImporterLibrary* ImportAudioFromFile(const FString& FilePath, TEnumAsByte<AudioFormat> Format,
bool DefineFormatAutomatically);
/** /**
* Destroy USoundWave static object. After the Soundwave is no longer needed, you need to call this function to free memory * Destroy USoundWave static object. After the Soundwave is no longer needed, you need to call this function to free memory
@@ -106,19 +110,22 @@ public:
* @return Whether the save was successfull or not * @return Whether the save was successfull or not
* @warning It is very important that USoundWave should not used by the engine so that it can be read from physical memory. * @warning It is very important that USoundWave should not used by the engine so that it can be read from physical memory.
*/ */
UFUNCTION(BlueprintCallable, meta = (Keywords = "Exporter, Export, Save, Runtime, WAV"), Category = "RuntimeAudioImporter") UFUNCTION(BlueprintCallable, meta = (Keywords = "Exporter, Export, Save, Runtime, WAV"), Category =
"RuntimeAudioImporter")
static bool ExportSoundWaveToFile(USoundWave* SoundWaveToExport, FString PathToExport); static bool ExportSoundWaveToFile(USoundWave* SoundWaveToExport, FString PathToExport);
private: private:
/** /**
* Internal main audio transcoding function * Internal main audio transcoding function
* *
* @param filePath Path to the audio file to import * @param FilePath Path to the audio file to import
* @param Format Audio file format (extension) * @param Format Audio file format (extension)
* @param DefineFormatAutomatically Whether to define format (extension) automatically or not * @param DefineFormatAutomatically Whether to define format (extension) automatically or not
* @return Returns itself * @return Returns itself
*/ */
URuntimeAudioImporterLibrary * GetUSoundWaveFromAudioFile_Internal(const FString & filePath, TEnumAsByte < AudioFormat > Format, bool DefineFormatAutomatically); URuntimeAudioImporterLibrary* GetUSoundWaveFromAudioFile_Internal(const FString& FilePath,
TEnumAsByte<AudioFormat> Format,
bool DefineFormatAutomatically);
/** /**
* Get USoundWave static object reference from 16-bit WAV data * Get USoundWave static object reference from 16-bit WAV data
@@ -128,12 +135,13 @@ private:
* @param Status Reference to TranscodingStatus Enumerator in case an error occurs * @param Status Reference to TranscodingStatus Enumerator in case an error occurs
* @return Returns a ready USoundWave object * @return Returns a ready USoundWave object
*/ */
class USoundWave* GetSoundWaveObject(const uint8 * WaveData, int32 WaveDataSize, TEnumAsByte < TranscodingStatus > & Status); class USoundWave* GetSoundWaveObject(const uint8* WaveData, int32 WaveDataSize,
TEnumAsByte<TranscodingStatus>& Status);
/** /**
* Transcode Audio from File to PCM Data * Transcode Audio from File to PCM Data
* *
* @param filePath Path to the audio file from which to receive PCM data * @param FilePath Path to the audio file from which to receive PCM data
* @param Format Format of the audio file (e.g. mp3. flac, etc) * @param Format Format of the audio file (e.g. mp3. flac, etc)
* @param Status Reference to TranscodingStatus Enumerator in case an error occurs * @param Status Reference to TranscodingStatus Enumerator in case an error occurs
* @param framesToWrite PCM frames ready to be written * @param framesToWrite PCM frames ready to be written
@@ -142,7 +150,9 @@ private:
* @param sampleRate Sample rate of the audio * @param sampleRate Sample rate of the audio
* @return Whether the transcoding was successful or not * @return Whether the transcoding was successful or not
*/ */
bool TranscodeAudioFileToPCMData(const wchar_t* filePath, TEnumAsByte < AudioFormat > Format, TEnumAsByte < TranscodingStatus > & Status, uint64 & framesToWrite, int16_t * &pSampleData, uint32 & channels, uint32 & sampleRate); bool TranscodeAudioFileToPCMData(FString FilePath, TEnumAsByte<AudioFormat> Format,
TEnumAsByte<TranscodingStatus>& Status, uint64& framesToWrite,
int16_t* & pSampleData, uint32& channels, uint32& sampleRate);
/** /**
* Transcode Audio from PCM to 16-bit WAV data * Transcode Audio from PCM to 16-bit WAV data
@@ -155,13 +165,14 @@ private:
* @param sampleRate Sample rate of the audio * @param sampleRate Sample rate of the audio
* @return Whether the transcoding was successful or not * @return Whether the transcoding was successful or not
*/ */
bool TranscodePCMToWAVData(void*& WaveData, size_t & WaveDataSize, uint64 framesToWrite, int16_t * &pSampleData, uint32 channels, uint32 sampleRate); bool TranscodePCMToWAVData(void*& WaveData, size_t& WaveDataSize, uint64 framesToWrite, int16_t* & pSampleData,
uint32 channels, uint32 sampleRate);
/** /**
* @param filePath File path, where to find the format (by extension) * @param FilePath File path, where to find the format (by extension)
* @return Returns the found audio format (e.g. mp3. flac, etc) by AudioFormat Enumerator * @return Returns the found audio format (e.g. mp3. flac, etc) by AudioFormat Enumerator
*/ */
static TEnumAsByte<AudioFormat> GetAudioFormat(const FString & filePath); static TEnumAsByte<AudioFormat> GetAudioFormat(const FString& FilePath);
/** /**
* Audio transcoding progress callback * Audio transcoding progress callback