Loading Raw WAV in runtime into USoundWave.

Hello!

I am trying to load a Wav file in runtime and convert it to USounWave to play it in game.
I have this code:


 USoundWave* UVBlueprintFunctionLibrary::GetSoundWaveFromRawData(TArray<uint8> Bytes)
 {
     USoundWave* sw = NewObject<USoundWave>(USoundWave::StaticClass());

         if (!sw)
             return nullptr;

     TArray < uint8 > rawFile;
     rawFile = Bytes;
     //FFileHelper::LoadFileToArray(rawFile, filePath.GetCharArray().GetData());
     FWaveModInfo WaveInfo;

     if (WaveInfo.ReadWaveInfo(rawFile.GetData(), rawFile.Num()))
     {
         sw->InvalidateCompressedData();

         sw->RawData.Lock(LOCK_READ_WRITE);
         void* LockedData = sw->RawData.Realloc(rawFile.Num());
         FMemory::Memcpy(LockedData, rawFile.GetData(), rawFile.Num());
         sw->RawData.Unlock();

         int32 DurationDiv = *WaveInfo.pChannels * *WaveInfo.pBitsPerSample * *WaveInfo.pSamplesPerSec;
         if (DurationDiv)
         {
             sw->Duration = *WaveInfo.pWaveDataSize * 8.0f / DurationDiv;
         }
         else
         {
             sw->Duration = 0.0f;
         }
         sw->SetSampleRate(*WaveInfo.pSamplesPerSec);
         sw->NumChannels = *WaveInfo.pChannels;
         sw->RawPCMDataSize = WaveInfo.SampleDataSize;
         sw->SoundGroup = ESoundGroup::SOUNDGROUP_Default;

     }
     else {
         return nullptr;
     }

     return sw;
 }

This code works in editor. I can put a array of uint8 into function and it returns USoundWave I can play. However, when i Package game, I cannot hear anything. Any idea why this works inside PIE but on in packaged game?

Thanks!

If it’s working in the editor but not the game, are you sure the packaged game is trying to load the file from its actual location? If you’re using the relative path, try using the absolute path for testing purposes or send a log message to confirm that you actually found it. You probably already ruled this most obvious step out, but hey, you never know.

thanks. Yes I am sure. I am connecting to back-end that answers by delegate, sending array of uint8. So I am not loading sound from file. Back end connection works because I get message from there with filled array.

@Frisco, did you ever you come across a solution to this?

Excuse me: Is your problem solved? I also encountered the same problem as you: The .Wav file was read from the outside and the USoundWave was created for playback. The problem is that it works fine when I use the “play” feature of the editor, I can hear the sound, but if I package it, I will get Three errors. Can anyone help me?

LogAudio: Error: Attempt to access the DDC when there is none available on sound ‘SoundWave /Script/Engine.SoundWave:SoundWave_2147482554’, format = OGG. Should have been cooked.
LogAudio: Error: FVorbisAudioInfo::ReadCompressedInfo, ov_open_callbacks error code: -132
LogAudio: Error: Failed to parse header for compressed vorbis file.

For anybody interested in this: I found a way to make it work in a packaged game with shipping configuration in UE 4.25.3: Instead of writing to USoundWave::RawData you need to write to USoundWave::RawPCMData. Here is an example:


USoundWave* WavDataToSoundwave(const TArray<uint8>& Data)
{ FWaveModInfo WaveInfo;
if (WaveInfo.ReadWaveInfo(Data.GetData(), Data.Num()))
{
  [INDENT=2]USoundWave* SoundWave = NewObject<USoundWave>();

// From FSoundWavePCMWriter::ApplyBufferToSoundWave() UE4.24
SoundWave->SetSampleRate(*WaveInfo.pSamplesPerSec);
SoundWave->NumChannels = *WaveInfo.pChannels;

const int32 BytesDataPerSecond = *WaveInfo.pChannels * (*WaveInfo.pBitsPerSample / 8.f) * *WaveInfo.pSamplesPerSec;
if (BytesDataPerSecond)
{[/INDENT]
  [INDENT=3]SoundWave->Duration = WaveInfo.SampleDataSize / BytesDataPerSecond;[/INDENT]
  [INDENT=2]}

SoundWave->RawPCMDataSize = WaveInfo.SampleDataSize;

SoundWave->RawPCMData = static_cast<uint8*>(FMemory::Malloc(WaveInfo.SampleDataSize));
FMemory::Memcpy(SoundWave->RawPCMData, WaveInfo.SampleDataStart, WaveInfo.SampleDataSize);
return SoundWave;[/INDENT]
  }
else
{
  [INDENT=2]return nullptr;[/INDENT]
  }
 }

5 Likes

Oh my God. Thank you so much i spent hours looking for this and your code actually works. Amazing!

We have a ready-made plugin available that can provide a solution.