How to get imported file bytes from USoundWave ?

I solved the problem by recreating the header myself using SampleRate and the Channels amount. It seems to work for basic PCM-16bit depth wave files, which is enough for me. Here is the code to do so (functions are static because it’s in a BP static library):

→ Please note that the function GetImportedSoundWaveData() is only available in editor mode, meaning that the code below will not work on packaged projects.

.h :

static TArray<uint8> SoundWaveToBytes(const USoundWave* Audio);
static TArray<uint8> FStringToBytes(const FString& String);
static TArray<uint8> uint32ToBytes(const uint32 Value, bool UseLittleEndian = true);
static TArray<uint8> uint16ToBytes(const uint16 Value, bool UseLittleEndian = true);

.cpp :

TArray<uint8> SoundWaveToBytes(const USoundWave* Audio)
{
	TArray<uint8> BytesArr;
	if (IsValid(Audio))
	{
		TArray<uint8> AudioBytes;
		TArray<uint8> AudioHeader;
		uint32 SampleRate;
		uint16 BitDepth = 16; // How to retrieve information directly from the SoundWave ??
		uint16 Channels;

		if (Audio->GetImportedSoundWaveData(AudioBytes, SampleRate, Channels))
		{
			// Please see: https://docs.fileformat.com/audio/wav/							   Bytes
			AudioHeader.Append(FStringToBytes("RIFF"));								// 1-4
			AudioHeader.Append(uint32ToBytes(AudioBytes.Num() + 36));					// 5-8
			AudioHeader.Append(FStringToBytes("WAVEfmt "));							// 9-16
			AudioHeader.Append(uint32ToBytes(16));										// 17-20
			AudioHeader.Append(uint16ToBytes(1));									// 21-22
			AudioHeader.Append(uint16ToBytes(Channels));								// 23-24
			AudioHeader.Append(uint32ToBytes(SampleRate));									// 25-28
			AudioHeader.Append(uint32ToBytes(SampleRate * BitDepth * Channels / 8));	// 29-32
			AudioHeader.Append(uint16ToBytes(BitDepth * Channels / 8));			// 33-34
			AudioHeader.Append(uint16ToBytes(BitDepth));								// 35-36
			AudioHeader.Append(FStringToBytes("data"));								// 37-40
			AudioHeader.Append(uint32ToBytes(AudioBytes.Num()));						// 41-44

			BytesArr.Append(AudioHeader);
			BytesArr.Append(AudioBytes);
		}
	}
	return BytesArr;
}



TArray<uint8> FStringToBytes(const FString& String)
{
	TArray<uint8> OutBytes;

	// Handle empty strings
	if (String.Len() > 0)
	{
		FTCHARToUTF8 Converted(*String); // Convert to UTF8
		OutBytes.Append(reinterpret_cast<const uint8*>(Converted.Get()), Converted.Length());
	}

	return OutBytes;
}

TArray<uint8> uint32ToBytes(const uint32 Value, bool UseLittleEndian)
{
	TArray<uint8> OutBytes;
	if (UseLittleEndian)
	{
		OutBytes.Add(Value >> 0 & 0xFF);
		OutBytes.Add(Value >> 8 & 0xFF);
		OutBytes.Add(Value >> 16 & 0xFF);
		OutBytes.Add(Value >> 24 & 0xFF);
	}
	else
	{
		OutBytes.Add(Value >> 24 & 0xFF);
		OutBytes.Add(Value >> 16 & 0xFF);
		OutBytes.Add(Value >> 8 & 0xFF);
		OutBytes.Add(Value >> 0 & 0xFF);
	}
	return OutBytes;
}

TArray<uint8> uint16ToBytes(const uint16 Value, bool UseLittleEndian)
{
	TArray<uint8> OutBytes;
	if (UseLittleEndian)
	{
		OutBytes.Add(Value >> 0 & 0xFF);
		OutBytes.Add(Value >> 8 & 0xFF);
	}
	else
	{
		OutBytes.Add(Value >> 8 & 0xFF);
		OutBytes.Add(Value >> 0 & 0xFF);
	}
	return OutBytes;
}

Usage :

USoundWave* Audio = ...;
TArray<uint8> AudioBytes = SoundWaveToBytes(Audio);

When I send the audio bytes in the HTTP POST multipart/form-data request (see this) the file is now readable by the server!

2 Likes