From c0943e2852c6de1da4758fb74ba3872dac534d80 Mon Sep 17 00:00:00 2001 From: Georgy Treshchev Date: Fri, 19 Feb 2021 10:08:21 +0100 Subject: [PATCH] Encoding changes, UNIX/Mac optimising --- .../Private/RuntimeAudioImporterLibrary.cpp | 378 +++++++++++------- .../Public/RuntimeAudioImporterLibrary.h | 83 ++-- 2 files changed, 270 insertions(+), 191 deletions(-) diff --git a/RuntimeAudioImporter/Source/RuntimeAudioImporter/Private/RuntimeAudioImporterLibrary.cpp b/RuntimeAudioImporter/Source/RuntimeAudioImporter/Private/RuntimeAudioImporterLibrary.cpp index 4c28a64..224cd14 100644 --- a/RuntimeAudioImporter/Source/RuntimeAudioImporter/Private/RuntimeAudioImporterLibrary.cpp +++ b/RuntimeAudioImporter/Source/RuntimeAudioImporter/Private/RuntimeAudioImporterLibrary.cpp @@ -5,7 +5,6 @@ URuntimeAudioImporterLibrary::URuntimeAudioImporterLibrary(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { - } URuntimeAudioImporterLibrary* URuntimeAudioImporterLibrary::CreateRuntimeAudioImporter() @@ -15,18 +14,20 @@ URuntimeAudioImporterLibrary* URuntimeAudioImporterLibrary::CreateRuntimeAudioIm return Importer; } -URuntimeAudioImporterLibrary* URuntimeAudioImporterLibrary::ImportAudioFromFile(const FString& filePath, TEnumAsByte < AudioFormat > Format, bool DefineFormatAutomatically) +URuntimeAudioImporterLibrary* URuntimeAudioImporterLibrary::ImportAudioFromFile( + const FString& FilePath, TEnumAsByte Format, bool DefineFormatAutomatically) { - AsyncTask(ENamedThreads::AnyThread, [=]() { - GetUSoundWaveFromAudioFile_Internal(filePath, Format, DefineFormatAutomatically); - }); + AsyncTask(ENamedThreads::AnyThread, [=]() + { + GetUSoundWaveFromAudioFile_Internal(FilePath, Format, DefineFormatAutomatically); + }); return this; } -bool URuntimeAudioImporterLibrary::DestroySoundWave(USoundWave* ReadySoundWave) { - - if (ReadySoundWave->IsValidLowLevel()) { - +bool URuntimeAudioImporterLibrary::DestroySoundWave(USoundWave* ReadySoundWave) +{ + if (ReadySoundWave->IsValidLowLevel()) + { //Begin USoundWave destroy (block changing some data) ReadySoundWave->ConditionalBeginDestroy(); ReadySoundWave->BeginDestroy(); @@ -34,9 +35,10 @@ bool URuntimeAudioImporterLibrary::DestroySoundWave(USoundWave* ReadySoundWave) //Delete all audio data from physical memory ReadySoundWave->RawData.RemoveBulkData(); ReadySoundWave->RemoveAudioResource(); - AsyncTask(ENamedThreads::AudioThread, [=]() { + AsyncTask(ENamedThreads::AudioThread, [=]() + { ReadySoundWave->InvalidateCompressedData(true); - }); + }); //Finish USoundWave destroy (complete object deletion as UObject) ReadySoundWave->IsReadyForFinishDestroy(); //This is not needed for verification, but for the initial removal @@ -44,7 +46,8 @@ bool URuntimeAudioImporterLibrary::DestroySoundWave(USoundWave* ReadySoundWave) ReadySoundWave->FinishDestroy(); return true; } - else { + else + { return false; } } @@ -56,17 +59,19 @@ bool URuntimeAudioImporterLibrary::DestroySoundWave(USoundWave* ReadySoundWave) #include "ThirdParty/dr_mp3.h" #include "ThirdParty/dr_flac.h" - /** - * Replacing standard CPP memory functions (malloc, realloc, free) with memory management functions that are maintained by Epic as the engine evolves. - */ +/** + * Replacing standard CPP memory functions (malloc, realloc, free) with memory management functions that are maintained by Epic as the engine evolves. + */ void* unreal_malloc(size_t sz, void* pUserData) { return FMemory::Malloc(sz); } + void* unreal_realloc(void* p, size_t sz, void* pUserData) { return FMemory::Realloc(p, sz); } + void unreal_free(void* p, void* pUserData) { FMemory::Free(p); @@ -77,9 +82,6 @@ bool URuntimeAudioImporterLibrary::ExportSoundWaveToFile(USoundWave* SoundWaveTo uint8* PCMData = SoundWaveToExport->RawPCMData; size_t PCMDataSize = SoundWaveToExport->RawPCMDataSize; - uint32 SampleRate; - uint16 ChannelCount; - drwav_allocation_callbacks allocationCallbacksDecoding; allocationCallbacksDecoding.pUserData = NULL; allocationCallbacksDecoding.onMalloc = unreal_malloc; @@ -88,8 +90,9 @@ bool URuntimeAudioImporterLibrary::ExportSoundWaveToFile(USoundWave* SoundWaveTo drwav_uint64 framesToWrite = PCMDataSize / sizeof(DR_WAVE_FORMAT_PCM) / SoundWaveToExport->NumChannels; - ChannelCount = SoundWaveToExport->NumChannels; - SampleRate = FGenericPlatformMath::RoundToInt((framesToWrite / (float)SoundWaveToExport->GetDuration() * ChannelCount)); + uint16 ChannelCount = SoundWaveToExport->NumChannels; + uint32 SampleRate = FGenericPlatformMath::RoundToInt( + (framesToWrite / (float)SoundWaveToExport->GetDuration() * ChannelCount)); drwav wavEncode; @@ -100,7 +103,14 @@ bool URuntimeAudioImporterLibrary::ExportSoundWaveToFile(USoundWave* SoundWaveTo format.sampleRate = SampleRate; 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; } @@ -110,48 +120,61 @@ bool URuntimeAudioImporterLibrary::ExportSoundWaveToFile(USoundWave* SoundWaveTo return true; } -URuntimeAudioImporterLibrary* URuntimeAudioImporterLibrary::GetUSoundWaveFromAudioFile_Internal(const FString& filePath, TEnumAsByte < AudioFormat > Format, bool DefineFormatAutomatically) +URuntimeAudioImporterLibrary* URuntimeAudioImporterLibrary::GetUSoundWaveFromAudioFile_Internal( + const FString& FilePath, TEnumAsByte Format, bool DefineFormatAutomatically) { - TEnumAsByte < TranscodingStatus > Status; - if (FPaths::FileExists(filePath) != true) { + TEnumAsByte Status; + if (FPaths::FileExists(FilePath) != true) + { Status = TranscodingStatus::AudioDoesNotExist; // Callback Dispatcher OnResult OnResult_Internal(nullptr, Status); } - else { + else + { int16_t* pSampleData; uint64 framesToWrite; uint32 channels; uint32 sampleRate; - if (DefineFormatAutomatically) { - Format = GetAudioFormat(filePath); + if (DefineFormatAutomatically) + { + Format = GetAudioFormat(FilePath); } - if (Format == AudioFormat::INVALID) { + if (Format == AudioFormat::INVALID) + { Status = TranscodingStatus::InvalidAudioFormat; // Callback Dispatcher OnResult OnResult_Internal(nullptr, Status); } - else { - if (TranscodeAudioFileToPCMData((wchar_t*)filePath.GetCharArray().GetData(), Format, Status, framesToWrite, pSampleData, channels, sampleRate) == false) { + else + { + if (TranscodeAudioFileToPCMData(FilePath, Format, Status, framesToWrite, pSampleData, channels, sampleRate) + == false) + { // Callback Dispatcher OnResult OnResult_Internal(nullptr, Status); } - else { + else + { void* WaveData; size_t WaveDataSize; - if (TranscodePCMToWAVData(*&WaveData, *&WaveDataSize, framesToWrite, *&pSampleData, channels, sampleRate) == false) { + if (TranscodePCMToWAVData(*&WaveData, *&WaveDataSize, framesToWrite, *&pSampleData, channels, + sampleRate) == false) + { FMemory::Free(pSampleData); // Callback Dispatcher OnResult OnResult_Internal(nullptr, Status); } - else { - USoundWave* ReadyUSoundWave = GetSoundWaveObject((const uint8*)WaveData, WaveDataSize, Status); // A ready USoundWave static object + else + { + USoundWave* ReadyUSoundWave = GetSoundWaveObject((const uint8*)WaveData, WaveDataSize, Status); + // A ready USoundWave static object /* Free temporary transcoding data */ FMemory::Free(WaveData); @@ -164,18 +187,18 @@ URuntimeAudioImporterLibrary* URuntimeAudioImporterLibrary::GetUSoundWaveFromAud // Callback Dispatcher OnResult OnResult_Internal(ReadyUSoundWave, Status); } - - } } } return this; } -class USoundWave* URuntimeAudioImporterLibrary::GetSoundWaveObject(const uint8* WaveData, int32 WaveDataSize, TEnumAsByte < TranscodingStatus >& Status) +class USoundWave* URuntimeAudioImporterLibrary::GetSoundWaveObject(const uint8* WaveData, int32 WaveDataSize, + TEnumAsByte& Status) { USoundWave* sw = NewObject(USoundWave::StaticClass()); - if (!sw) { + if (!sw) + { Status = TranscodingStatus::USoundWaveDeclarationError; return nullptr; } @@ -190,7 +213,8 @@ class USoundWave* URuntimeAudioImporterLibrary::GetSoundWaveObject(const uint8* // Callback Dispatcher OnProgress (not completely accurate implementation) OnProgress_Internal(75); - if (*WaveInfo.pBitsPerSample != 16) { + if (*WaveInfo.pBitsPerSample != 16) + { Status = TranscodingStatus::UnsupportedBitDepth; return nullptr; } @@ -222,17 +246,25 @@ class USoundWave* URuntimeAudioImporterLibrary::GetSoundWaveObject(const uint8* // Callback Dispatcher OnProgress (not completely accurate implementation) OnProgress_Internal(85); } - else { - if (ErrorReason.Equals(TEXT("Invalid WAVE file."), ESearchCase::CaseSensitive)) { + else + { + if (ErrorReason.Equals(TEXT("Invalid WAVE file."), ESearchCase::CaseSensitive)) + { 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; } - 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; } - else { + else + { Status = TranscodingStatus::UnrecognizedReadWaveError; } return nullptr; @@ -248,7 +280,8 @@ class USoundWave* URuntimeAudioImporterLibrary::GetSoundWaveObject(const uint8* // Callback Dispatcher OnProgress (not completely accurate implementation) OnProgress_Internal(95); - if (!sw) { + if (!sw) + { Status = TranscodingStatus::InvalidUSoundWave; return nullptr; } @@ -256,123 +289,151 @@ class USoundWave* URuntimeAudioImporterLibrary::GetSoundWaveObject(const uint8* 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 Format, + TEnumAsByte& Status, + uint64& framesToWrite, int16_t*& pSampleData, + uint32& channels, uint32& sampleRate) { OnProgress_Internal(5); switch (Format) { case AudioFormat::MP3: - { - drmp3_allocation_callbacks allocationCallbacksDecoding; - allocationCallbacksDecoding.pUserData = NULL; - allocationCallbacksDecoding.onMalloc = unreal_malloc; - allocationCallbacksDecoding.onRealloc = unreal_realloc; - allocationCallbacksDecoding.onFree = unreal_free; + { + drmp3_allocation_callbacks allocationCallbacksDecoding; + allocationCallbacksDecoding.pUserData = NULL; + allocationCallbacksDecoding.onMalloc = unreal_malloc; + allocationCallbacksDecoding.onRealloc = unreal_realloc; + allocationCallbacksDecoding.onFree = unreal_free; - drmp3 mp3; - if (!drmp3_init_file_w(&mp3, filePath, &allocationCallbacksDecoding)) { - Status = TranscodingStatus::FailedToOpenStream; - return false; + drmp3 mp3; +#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; + return false; + } + else + { + // Callback Dispatcher OnProgress (not completely accurate implementation) + OnProgress_Internal(10); + + 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) + OnProgress_Internal(15); + + framesToWrite = drmp3_read_pcm_frames_s16(&mp3, drmp3_get_pcm_frame_count(&mp3), pSampleData); + + // Callback Dispatcher OnProgress (not completely accurate implementation) + OnProgress_Internal(35); + + channels = mp3.channels; + sampleRate = mp3.sampleRate; + drmp3_uninit(&mp3); + return true; + } + break; } - else { - // Callback Dispatcher OnProgress (not completely accurate implementation) - OnProgress_Internal(10); - - 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) - OnProgress_Internal(15); - - framesToWrite = drmp3_read_pcm_frames_s16(&mp3, drmp3_get_pcm_frame_count(&mp3), pSampleData); - - // Callback Dispatcher OnProgress (not completely accurate implementation) - OnProgress_Internal(35); - - channels = mp3.channels; - sampleRate = mp3.sampleRate; - drmp3_uninit(&mp3); - return true; - } - break; - } case AudioFormat::WAV: - { - drwav_allocation_callbacks allocationCallbacksDecoding; - allocationCallbacksDecoding.pUserData = NULL; - allocationCallbacksDecoding.onMalloc = unreal_malloc; - allocationCallbacksDecoding.onRealloc = unreal_realloc; - allocationCallbacksDecoding.onFree = unreal_free; + { + drwav_allocation_callbacks allocationCallbacksDecoding; + allocationCallbacksDecoding.pUserData = NULL; + allocationCallbacksDecoding.onMalloc = unreal_malloc; + allocationCallbacksDecoding.onRealloc = unreal_realloc; + allocationCallbacksDecoding.onFree = unreal_free; - drwav wav; - if (!drwav_init_file_w(&wav, filePath, &allocationCallbacksDecoding)) { - Status = TranscodingStatus::FailedToOpenStream; - return false; + drwav wav; +#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; + return false; + } + else + { + // Callback Dispatcher OnProgress (not completely accurate implementation) + OnProgress_Internal(10); + + pSampleData = (int16_t*) + FMemory::Malloc((size_t)wav.totalPCMFrameCount * wav.channels * sizeof(int16_t)); + + // Callback Dispatcher OnProgress (not completely accurate implementation) + OnProgress_Internal(15); + + framesToWrite = drwav_read_pcm_frames_s16(&wav, wav.totalPCMFrameCount, pSampleData); + + // Callback Dispatcher OnProgress (not completely accurate implementation) + OnProgress_Internal(35); + + channels = wav.channels; + sampleRate = wav.sampleRate; + drwav_uninit(&wav); + return true; + } + break; } - else { - // Callback Dispatcher OnProgress (not completely accurate implementation) - OnProgress_Internal(10); - - pSampleData = (int16_t*)FMemory::Malloc((size_t)wav.totalPCMFrameCount * wav.channels * sizeof(int16_t)); - - // Callback Dispatcher OnProgress (not completely accurate implementation) - OnProgress_Internal(15); - - framesToWrite = drwav_read_pcm_frames_s16(&wav, wav.totalPCMFrameCount, pSampleData); - - // Callback Dispatcher OnProgress (not completely accurate implementation) - OnProgress_Internal(35); - - channels = wav.channels; - sampleRate = wav.sampleRate; - drwav_uninit(&wav); - return true; - } - break; - } case AudioFormat::FLAC: - { - drflac_allocation_callbacks allocationCallbacksDecoding; - allocationCallbacksDecoding.pUserData = NULL; - allocationCallbacksDecoding.onMalloc = unreal_malloc; - allocationCallbacksDecoding.onRealloc = unreal_realloc; - allocationCallbacksDecoding.onFree = unreal_free; + { + drflac_allocation_callbacks allocationCallbacksDecoding; + allocationCallbacksDecoding.pUserData = NULL; + allocationCallbacksDecoding.onMalloc = unreal_malloc; + allocationCallbacksDecoding.onRealloc = unreal_realloc; + allocationCallbacksDecoding.onFree = unreal_free; - drflac* pFlac = drflac_open_file_w(filePath, &allocationCallbacksDecoding); - if (pFlac == NULL) { - Status = TranscodingStatus::FailedToOpenStream; - return false; +#if PLATFORM_WINDOWS + 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; + return false; + } + else + { + // Callback Dispatcher OnProgress (not completely accurate implementation) + OnProgress_Internal(10); + + pSampleData = (int16_t*)FMemory::Malloc( + (size_t)pFlac->totalPCMFrameCount * pFlac->channels * sizeof(int16_t)); + + // Callback Dispatcher OnProgress (not completely accurate implementation) + OnProgress_Internal(15); + + framesToWrite = drflac_read_pcm_frames_s16(pFlac, pFlac->totalPCMFrameCount, pSampleData); + + // Callback Dispatcher OnProgress (not completely accurate implementation) + OnProgress_Internal(35); + + channels = pFlac->channels; + sampleRate = pFlac->sampleRate; + drflac_close(pFlac); + return true; + } + break; } - else { - // Callback Dispatcher OnProgress (not completely accurate implementation) - OnProgress_Internal(10); - - pSampleData = (int16_t*)FMemory::Malloc((size_t)pFlac->totalPCMFrameCount * pFlac->channels * sizeof(int16_t)); - - // Callback Dispatcher OnProgress (not completely accurate implementation) - OnProgress_Internal(15); - - framesToWrite = drflac_read_pcm_frames_s16(pFlac, pFlac->totalPCMFrameCount, pSampleData); - - // Callback Dispatcher OnProgress (not completely accurate implementation) - OnProgress_Internal(35); - - channels = pFlac->channels; - sampleRate = pFlac->sampleRate; - drflac_close(pFlac); - return true; - } - break; - } default: - { - Status = TranscodingStatus::InvalidAudioFormat; - return false; - break; - } + { + Status = TranscodingStatus::InvalidAudioFormat; + return false; + break; + } } } -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_data_format format; format.container = drwav_container_riff; @@ -386,7 +447,8 @@ bool URuntimeAudioImporterLibrary::TranscodePCMToWAVData(void*& WaveData, size_t allocationCallbacks.onMalloc = unreal_malloc; allocationCallbacks.onRealloc = unreal_realloc; 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 } @@ -404,31 +466,37 @@ bool URuntimeAudioImporterLibrary::TranscodePCMToWAVData(void*& WaveData, size_t TEnumAsByte 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; } - 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; } - 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; } - else { + else + { return AudioFormat::INVALID; } } void URuntimeAudioImporterLibrary::OnProgress_Internal(int32 Percentage) { - AsyncTask(ENamedThreads::GameThread, [=]() { + AsyncTask(ENamedThreads::GameThread, [=]() + { OnProgress.Broadcast(Percentage); - }); + }); } -void URuntimeAudioImporterLibrary::OnResult_Internal(USoundWave* ReadySoundWave, TEnumAsByte < TranscodingStatus > Status) +void URuntimeAudioImporterLibrary::OnResult_Internal(USoundWave* ReadySoundWave, TEnumAsByte Status) { - AsyncTask(ENamedThreads::GameThread, [=]() { + AsyncTask(ENamedThreads::GameThread, [=]() + { RemoveFromRoot(); OnResult.Broadcast(ReadySoundWave, Status); - }); + }); } diff --git a/RuntimeAudioImporter/Source/RuntimeAudioImporter/Public/RuntimeAudioImporterLibrary.h b/RuntimeAudioImporter/Source/RuntimeAudioImporter/Public/RuntimeAudioImporterLibrary.h index 4eac9a8..082dca4 100644 --- a/RuntimeAudioImporter/Source/RuntimeAudioImporter/Public/RuntimeAudioImporterLibrary.h +++ b/RuntimeAudioImporter/Source/RuntimeAudioImporter/Public/RuntimeAudioImporterLibrary.h @@ -11,18 +11,18 @@ UENUM(BlueprintType, Category = "RuntimeAudioImporter") enum TranscodingStatus { - SuccessTranscoding UMETA(DisplayName = "Success"), - FailedToOpenStream UMETA(DisplayName = "Failed to open stream"), - UnsupportedBitDepth UMETA(DisplayName = "Unsupported bit depth (Unreal Engine only supports 16 bit)"), - InvalidWAVEData UMETA(DisplayName = "Invalid WAVE data"), - InvalidBitrate UMETA(DisplayName = "Invalid bitrate (Actual bit rate does not match the container size)"), - InvalidSubformat UMETA(DisplayName = "InvalidSubformat (Subformat identifier not recognized)"), - UnrecognizedReadWaveError UMETA(DisplayName = "Unrecognized ReadWave error"), - USoundWaveDeclarationError UMETA(DisplayName = "USoundWave declaration error"), - InvalidUSoundWave UMETA(DisplayName = "Invalid USoundWave (The USoundWave object contains incorrect data)"), - InvalidAudioFormat UMETA(DisplayName = "Invalid audio format (Can't determine the format of the audio file)"), - AudioDoesNotExist UMETA(DisplayName = "The audio file does not exist"), - ZeroDurationError UMETA(DisplayName = "Transcoded audio has zero length") + SuccessTranscoding UMETA(DisplayName = "Success"), + FailedToOpenStream UMETA(DisplayName = "Failed to open stream"), + UnsupportedBitDepth UMETA(DisplayName = "Unsupported bit depth (Unreal Engine only supports 16 bit)"), + InvalidWAVEData UMETA(DisplayName = "Invalid WAVE data"), + InvalidBitrate UMETA(DisplayName = "Invalid bitrate (Actual bit rate does not match the container size)"), + InvalidSubformat UMETA(DisplayName = "InvalidSubformat (Subformat identifier not recognized)"), + UnrecognizedReadWaveError UMETA(DisplayName = "Unrecognized ReadWave error"), + USoundWaveDeclarationError UMETA(DisplayName = "USoundWave declaration error"), + InvalidUSoundWave UMETA(DisplayName = "Invalid USoundWave (The USoundWave object contains incorrect data)"), + InvalidAudioFormat UMETA(DisplayName = "Invalid audio format (Can't determine the format of the audio file)"), + AudioDoesNotExist UMETA(DisplayName = "The audio file does not exist"), + ZeroDurationError UMETA(DisplayName = "Transcoded audio has zero length") }; /** @@ -31,10 +31,10 @@ enum TranscodingStatus UENUM(BlueprintType, Category = "RuntimeAudioImporter") enum AudioFormat { - MP3 UMETA(DisplayName = "mp3"), - WAV UMETA(DisplayName = "wav"), - FLAC UMETA(DisplayName = "flac"), - INVALID UMETA(DisplayName = "invalid (not defined format, internal use only)", Hidden) + MP3 UMETA(DisplayName = "mp3"), + WAV UMETA(DisplayName = "wav"), + FLAC UMETA(DisplayName = "flac"), + INVALID UMETA(DisplayName = "invalid (not defined format, internal use only)", Hidden) }; /** @@ -51,7 +51,8 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnProgress, const int32, Percentage * @param ReadySoundWave Ready USoundWave Object * @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") class RUNTIMEAUDIOIMPORTER_API URuntimeAudioImporterLibrary : public UObject @@ -62,32 +63,35 @@ public: * Bind to know when the transcoding is on progress. */ UPROPERTY(BlueprintAssignable, Category = "RuntimeAudioImporter") - FOnProgress OnProgress; + FOnProgress OnProgress; /** * Bind to know when the transcoding is complete (even if it fails). */ UPROPERTY(BlueprintAssignable, Category = "RuntimeAudioImporter") - FOnResult OnResult; + FOnResult OnResult; /** * Instantiates a RuntimeAudioImporter object. * * @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") - static URuntimeAudioImporterLibrary * CreateRuntimeAudioImporter(); + UFUNCTION(BlueprintCallable, meta = (Keywords = "Create, Audio, Runtime, MP3, FLAC, WAV"), Category = + "RuntimeAudioImporter") + static URuntimeAudioImporterLibrary* CreateRuntimeAudioImporter(); /** * 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 DefineFormatAutomatically Whether to define format (extension) automatically or not * @return Returns itself. */ - UFUNCTION(BlueprintCallable, meta = (Keywords = "Importer, Transcoder, Converter, Runtime, MP3, FLAC, WAV"), Category = "RuntimeAudioImporter") - URuntimeAudioImporterLibrary * ImportAudioFromFile(const FString & filePath, TEnumAsByte < AudioFormat > Format, bool DefineFormatAutomatically); + UFUNCTION(BlueprintCallable, meta = (Keywords = "Importer, Transcoder, Converter, Runtime, MP3, FLAC, WAV"), + Category = "RuntimeAudioImporter") + URuntimeAudioImporterLibrary* ImportAudioFromFile(const FString& FilePath, TEnumAsByte Format, + bool DefineFormatAutomatically); /** * Destroy USoundWave static object. After the Soundwave is no longer needed, you need to call this function to free memory @@ -96,7 +100,7 @@ public: * @return Whether the descruction of USoundWave was successful or not */ UFUNCTION(BlueprintCallable, meta = (Keywords = "MP3, FLAC, WAV, Destroy"), Category = "RuntimeAudioImporter") - static bool DestroySoundWave(USoundWave * ReadySoundWave); + static bool DestroySoundWave(USoundWave* ReadySoundWave); /** * Export (save) SoundWave object to .WAV audio file to device memory. So far beta and it is not recommended to use due to the fact that the engine can clear the sound data itself @@ -106,19 +110,22 @@ public: * @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. */ - UFUNCTION(BlueprintCallable, meta = (Keywords = "Exporter, Export, Save, Runtime, WAV"), Category = "RuntimeAudioImporter") - static bool ExportSoundWaveToFile(USoundWave * SoundWaveToExport, FString PathToExport); + UFUNCTION(BlueprintCallable, meta = (Keywords = "Exporter, Export, Save, Runtime, WAV"), Category = + "RuntimeAudioImporter") + static bool ExportSoundWaveToFile(USoundWave* SoundWaveToExport, FString PathToExport); private: /** * 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 DefineFormatAutomatically Whether to define format (extension) automatically or not * @return Returns itself */ - URuntimeAudioImporterLibrary * GetUSoundWaveFromAudioFile_Internal(const FString & filePath, TEnumAsByte < AudioFormat > Format, bool DefineFormatAutomatically); + URuntimeAudioImporterLibrary* GetUSoundWaveFromAudioFile_Internal(const FString& FilePath, + TEnumAsByte Format, + bool DefineFormatAutomatically); /** * 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 * @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& Status); /** * 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 Status Reference to TranscodingStatus Enumerator in case an error occurs * @param framesToWrite PCM frames ready to be written @@ -142,7 +150,9 @@ private: * @param sampleRate Sample rate of the audio * @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 Format, + TEnumAsByte& Status, uint64& framesToWrite, + int16_t* & pSampleData, uint32& channels, uint32& sampleRate); /** * Transcode Audio from PCM to 16-bit WAV data @@ -155,13 +165,14 @@ private: * @param sampleRate Sample rate of the audio * @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 */ - static TEnumAsByte GetAudioFormat(const FString & filePath); + static TEnumAsByte GetAudioFormat(const FString& FilePath); /** * Audio transcoding progress callback @@ -175,5 +186,5 @@ private: * @param ReadySoundWave A ready USoundWave object * @param Status Reference to TranscodingStatus Enumerator */ - void OnResult_Internal(USoundWave * ReadySoundWave, TEnumAsByte < TranscodingStatus > Status); + void OnResult_Internal(USoundWave* ReadySoundWave, TEnumAsByte Status); };