mirror of
https://github.com/storytold/RuntimeAudioImporter.git
synced 2026-10-18 07:40:28 +00:00
Encoding changes, UNIX/Mac optimising
This commit is contained in:
+223
-155
@@ -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,9 +35,10 @@ 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);
|
||||||
});
|
});
|
||||||
|
|
||||||
//Finish USoundWave destroy (complete object deletion as UObject)
|
//Finish USoundWave destroy (complete object deletion as UObject)
|
||||||
ReadySoundWave->IsReadyForFinishDestroy(); //This is not needed for verification, but for the initial removal
|
ReadySoundWave->IsReadyForFinishDestroy(); //This is not needed for verification, but for the initial removal
|
||||||
@@ -44,7 +46,8 @@ bool URuntimeAudioImporterLibrary::DestroySoundWave(USoundWave* ReadySoundWave)
|
|||||||
ReadySoundWave->FinishDestroy();
|
ReadySoundWave->FinishDestroy();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,17 +59,19 @@ bool URuntimeAudioImporterLibrary::DestroySoundWave(USoundWave* ReadySoundWave)
|
|||||||
#include "ThirdParty/dr_mp3.h"
|
#include "ThirdParty/dr_mp3.h"
|
||||||
#include "ThirdParty/dr_flac.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)
|
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,123 +289,151 @@ 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)
|
||||||
{
|
{
|
||||||
case AudioFormat::MP3:
|
case AudioFormat::MP3:
|
||||||
{
|
{
|
||||||
drmp3_allocation_callbacks allocationCallbacksDecoding;
|
drmp3_allocation_callbacks allocationCallbacksDecoding;
|
||||||
allocationCallbacksDecoding.pUserData = NULL;
|
allocationCallbacksDecoding.pUserData = NULL;
|
||||||
allocationCallbacksDecoding.onMalloc = unreal_malloc;
|
allocationCallbacksDecoding.onMalloc = unreal_malloc;
|
||||||
allocationCallbacksDecoding.onRealloc = unreal_realloc;
|
allocationCallbacksDecoding.onRealloc = unreal_realloc;
|
||||||
allocationCallbacksDecoding.onFree = unreal_free;
|
allocationCallbacksDecoding.onFree = unreal_free;
|
||||||
|
|
||||||
drmp3 mp3;
|
drmp3 mp3;
|
||||||
if (!drmp3_init_file_w(&mp3, filePath, &allocationCallbacksDecoding)) {
|
#if PLATFORM_WINDOWS
|
||||||
Status = TranscodingStatus::FailedToOpenStream;
|
if (!drmp3_init_file_w(&mp3, (wchar_t*)FilePath.GetCharArray().GetData(), &allocationCallbacksDecoding))
|
||||||
return false;
|
#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:
|
case AudioFormat::WAV:
|
||||||
{
|
{
|
||||||
drwav_allocation_callbacks allocationCallbacksDecoding;
|
drwav_allocation_callbacks allocationCallbacksDecoding;
|
||||||
allocationCallbacksDecoding.pUserData = NULL;
|
allocationCallbacksDecoding.pUserData = NULL;
|
||||||
allocationCallbacksDecoding.onMalloc = unreal_malloc;
|
allocationCallbacksDecoding.onMalloc = unreal_malloc;
|
||||||
allocationCallbacksDecoding.onRealloc = unreal_realloc;
|
allocationCallbacksDecoding.onRealloc = unreal_realloc;
|
||||||
allocationCallbacksDecoding.onFree = unreal_free;
|
allocationCallbacksDecoding.onFree = unreal_free;
|
||||||
|
|
||||||
drwav wav;
|
drwav wav;
|
||||||
if (!drwav_init_file_w(&wav, filePath, &allocationCallbacksDecoding)) {
|
#if PLATFORM_WINDOWS
|
||||||
Status = TranscodingStatus::FailedToOpenStream;
|
if (!drwav_init_file_w(&wav, (wchar_t*)FilePath.GetCharArray().GetData(), &allocationCallbacksDecoding))
|
||||||
return false;
|
#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:
|
case AudioFormat::FLAC:
|
||||||
{
|
{
|
||||||
drflac_allocation_callbacks allocationCallbacksDecoding;
|
drflac_allocation_callbacks allocationCallbacksDecoding;
|
||||||
allocationCallbacksDecoding.pUserData = NULL;
|
allocationCallbacksDecoding.pUserData = NULL;
|
||||||
allocationCallbacksDecoding.onMalloc = unreal_malloc;
|
allocationCallbacksDecoding.onMalloc = unreal_malloc;
|
||||||
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(),
|
||||||
Status = TranscodingStatus::FailedToOpenStream;
|
&allocationCallbacksDecoding);
|
||||||
return false;
|
#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:
|
default:
|
||||||
{
|
{
|
||||||
Status = TranscodingStatus::InvalidAudioFormat;
|
Status = TranscodingStatus::InvalidAudioFormat;
|
||||||
return false;
|
return false;
|
||||||
break;
|
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 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,31 +466,37 @@ 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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+47
-36
@@ -11,18 +11,18 @@
|
|||||||
UENUM(BlueprintType, Category = "RuntimeAudioImporter")
|
UENUM(BlueprintType, Category = "RuntimeAudioImporter")
|
||||||
enum TranscodingStatus
|
enum TranscodingStatus
|
||||||
{
|
{
|
||||||
SuccessTranscoding UMETA(DisplayName = "Success"),
|
SuccessTranscoding UMETA(DisplayName = "Success"),
|
||||||
FailedToOpenStream UMETA(DisplayName = "Failed to open stream"),
|
FailedToOpenStream UMETA(DisplayName = "Failed to open stream"),
|
||||||
UnsupportedBitDepth UMETA(DisplayName = "Unsupported bit depth (Unreal Engine only supports 16 bit)"),
|
UnsupportedBitDepth UMETA(DisplayName = "Unsupported bit depth (Unreal Engine only supports 16 bit)"),
|
||||||
InvalidWAVEData UMETA(DisplayName = "Invalid WAVE data"),
|
InvalidWAVEData UMETA(DisplayName = "Invalid WAVE data"),
|
||||||
InvalidBitrate UMETA(DisplayName = "Invalid bitrate (Actual bit rate does not match the container size)"),
|
InvalidBitrate UMETA(DisplayName = "Invalid bitrate (Actual bit rate does not match the container size)"),
|
||||||
InvalidSubformat UMETA(DisplayName = "InvalidSubformat (Subformat identifier not recognized)"),
|
InvalidSubformat UMETA(DisplayName = "InvalidSubformat (Subformat identifier not recognized)"),
|
||||||
UnrecognizedReadWaveError UMETA(DisplayName = "Unrecognized ReadWave error"),
|
UnrecognizedReadWaveError UMETA(DisplayName = "Unrecognized ReadWave error"),
|
||||||
USoundWaveDeclarationError UMETA(DisplayName = "USoundWave declaration error"),
|
USoundWaveDeclarationError UMETA(DisplayName = "USoundWave declaration error"),
|
||||||
InvalidUSoundWave UMETA(DisplayName = "Invalid USoundWave (The USoundWave object contains incorrect data)"),
|
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)"),
|
InvalidAudioFormat UMETA(DisplayName = "Invalid audio format (Can't determine the format of the audio file)"),
|
||||||
AudioDoesNotExist UMETA(DisplayName = "The audio file does not exist"),
|
AudioDoesNotExist UMETA(DisplayName = "The audio file does not exist"),
|
||||||
ZeroDurationError UMETA(DisplayName = "Transcoded audio has zero length")
|
ZeroDurationError UMETA(DisplayName = "Transcoded audio has zero length")
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,10 +31,10 @@ enum TranscodingStatus
|
|||||||
UENUM(BlueprintType, Category = "RuntimeAudioImporter")
|
UENUM(BlueprintType, Category = "RuntimeAudioImporter")
|
||||||
enum AudioFormat
|
enum AudioFormat
|
||||||
{
|
{
|
||||||
MP3 UMETA(DisplayName = "mp3"),
|
MP3 UMETA(DisplayName = "mp3"),
|
||||||
WAV UMETA(DisplayName = "wav"),
|
WAV UMETA(DisplayName = "wav"),
|
||||||
FLAC UMETA(DisplayName = "flac"),
|
FLAC UMETA(DisplayName = "flac"),
|
||||||
INVALID UMETA(DisplayName = "invalid (not defined format, internal use only)", Hidden)
|
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 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
|
||||||
@@ -62,32 +63,35 @@ public:
|
|||||||
* Bind to know when the transcoding is on progress.
|
* Bind to know when the transcoding is on progress.
|
||||||
*/
|
*/
|
||||||
UPROPERTY(BlueprintAssignable, Category = "RuntimeAudioImporter")
|
UPROPERTY(BlueprintAssignable, Category = "RuntimeAudioImporter")
|
||||||
FOnProgress OnProgress;
|
FOnProgress OnProgress;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind to know when the transcoding is complete (even if it fails).
|
* Bind to know when the transcoding is complete (even if it fails).
|
||||||
*/
|
*/
|
||||||
UPROPERTY(BlueprintAssignable, Category = "RuntimeAudioImporter")
|
UPROPERTY(BlueprintAssignable, Category = "RuntimeAudioImporter")
|
||||||
FOnResult OnResult;
|
FOnResult OnResult;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a RuntimeAudioImporter object.
|
* 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.
|
* @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 =
|
||||||
static URuntimeAudioImporterLibrary * CreateRuntimeAudioImporter();
|
"RuntimeAudioImporter")
|
||||||
|
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
|
||||||
@@ -96,7 +100,7 @@ public:
|
|||||||
* @return Whether the descruction of USoundWave was successful or not
|
* @return Whether the descruction of USoundWave was successful or not
|
||||||
*/
|
*/
|
||||||
UFUNCTION(BlueprintCallable, meta = (Keywords = "MP3, FLAC, WAV, Destroy"), Category = "RuntimeAudioImporter")
|
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
|
* 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
|
* @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 =
|
||||||
static bool ExportSoundWaveToFile(USoundWave * SoundWaveToExport, FString PathToExport);
|
"RuntimeAudioImporter")
|
||||||
|
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
|
||||||
@@ -175,5 +186,5 @@ private:
|
|||||||
* @param ReadySoundWave A ready USoundWave object
|
* @param ReadySoundWave A ready USoundWave object
|
||||||
* @param Status Reference to TranscodingStatus Enumerator
|
* @param Status Reference to TranscodingStatus Enumerator
|
||||||
*/
|
*/
|
||||||
void OnResult_Internal(USoundWave * ReadySoundWave, TEnumAsByte < TranscodingStatus > Status);
|
void OnResult_Internal(USoundWave* ReadySoundWave, TEnumAsByte<TranscodingStatus> Status);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user