Voice record in multiplayer during gameplay. Saving it in a binary and playing the audio back gives garbage sound play

Every tick you are overwriting VoiceCaptureBuffer, so at most you are only saving one ticks worth of data. Instead you should be adding to the end of VoiceCaptureBuffer.

VoiceCaptureReadBytes = sizeof(uint8)*Var.Num()*2000;

This explains the garbage sound. Var is actually very short but you’re loading 2000 times as much random memory data into the queue. This should just be sizeof(uint8) * Var.Num().

My aim is to record player voices when record gameplay is initiated. I wish to save the recorded voice as a binary file, and replay it back.
I have used https://answers.unrealengine.com/questions/347976/basic-microphone-input-with-ue4.html tutorial to play the recorded audio. Works fine.

void AVoiceRecordTest::VoiceCaptureTick()
{
    if (!VoiceCapture.IsValid())
        return;

    uint32 VoiceCaptureBytesAvailable = 0;
    EVoiceCaptureState::Type CaptureState = VoiceCapture->GetCaptureState(VoiceCaptureBytesAvailable);

        uint32 VoiceCaptureReadBytes = 100;
        VoiceCaptureBuffer.SetNumUninitialized(VoiceCaptureBytesAvailable);
        VoiceCapture->GetVoiceData(VoiceCaptureBuffer.GetData(), VoiceCaptureBytesAvailable, VoiceCaptureReadBytes);
        VoiceCaptureSoundWaveProcedural->QueueAudio(VoiceCaptureBuffer.GetData(), VoiceCaptureReadBytes);
}

The above function is being called on every tick. Works fine!

Next I tried to save the recorded audio in binary format and retrieve the data back using this tutorial A new, community-hosted Unreal Engine Wiki - Announcements - Epic Developer Community Forums
I get the same data which I saved. But when I queue the sound and play it, garage sound plays.

    VoiceCaptureSoundWaveProcedural->QueueAudio(Var.GetData(), VoiceCaptureReadBytes); //var has the retrieved data
    VoiceCaptureAudioComponent->SetSound(VoiceCaptureSoundWaveProcedural);
    VoiceCaptureAudioComponent->Play();

all the above is happening in a single function which is called once.

attaching the links to
.h file:
.cpp file: VoiceRecordTest.cpp - Pastebin.com

Is there any other approach to do the same. Also let me know if anyone can find my mistake here.

I initially did sizeof(uint8) * Var.Num(). But the result was same. And hence thought the size might not be sufficient so increased it. But same result in both the cases.
I think the problem might be that I am saying overwrite what is in VoiceCaptureBuffer. So what I am writing to disk is only the last chunk of audio you got from the input device
I should try concatenate VoiceCaptureBuffer to a larger buffer, then save that buffer to disk. (Source: Discord)
I’ll try this out and post if it works.

No change in the result. Here I have appended the voice data into a new array and saved it in a binary file. Retrieving the same gives garbage sound when played

void AVoiceRecordTest::VoiceCaptureTick()
{
    if (!VoiceCapture.IsValid())
        return;

    uint32 VoiceCaptureBytesAvailable = 0;
    EVoiceCaptureState::Type CaptureState = VoiceCapture->GetCaptureState(VoiceCaptureBytesAvailable);

        uint32 VoiceCaptureReadBytes = 10000;
        VoiceCaptureBuffer.SetNumUninitialized(VoiceCaptureBytesAvailable);
        VoiceCapture->GetVoiceData(VoiceCaptureBuffer.GetData(), VoiceCaptureBytesAvailable, VoiceCaptureReadBytes);
        TArray<uint8> NewAudioBuffer;
        NewAudioBuffer.AddUninitialized(VoiceCaptureReadBytes);
        FMemory::Memcpy(NewAudioBuffer.GetData(), VoiceCaptureBuffer.GetData(), VoiceCaptureReadBytes);
        VoiceCaptureBufferAppended.Append(NewAudioBuffer);  //appending the voicedata to a new array
        //VoiceCaptureSoundWaveProcedural->QueueAudio(VoiceCaptureBuffer.GetData(), VoiceCaptureReadBytes);
}

I am also getting a garbage audio? You found something on this?

This works! :slight_smile: The trick is to append the data to a new array and save it properly. also you need to reduce the increase the microphone boost in your recording settings, because unreal chops the sound below a certain level.

void AVoiceRecordTest::VoiceCaptureTick()
    {
        if (!VoiceCapture.IsValid())
            return;
    
        uint32 VoiceCaptureBytesAvailable = 0;
        EVoiceCaptureState::Type CaptureState = VoiceCapture->GetCaptureState(VoiceCaptureBytesAvailable);
    
            uint32 VoiceCaptureReadBytes = 10000;
            VoiceCaptureBuffer.SetNumUninitialized(VoiceCaptureBytesAvailable);
            VoiceCapture->GetVoiceData(VoiceCaptureBuffer.GetData(), VoiceCaptureBytesAvailable, VoiceCaptureReadBytes);
            TArray<uint8> NewAudioBuffer;
            NewAudioBuffer.AddUninitialized(VoiceCaptureReadBytes);
            FMemory::Memcpy(NewAudioBuffer.GetData(), VoiceCaptureBuffer.GetData(), VoiceCaptureReadBytes);
            VoiceCaptureBufferAppended.Append(NewAudioBuffer);
    }

    //STOP RECORDING AND SAVE IN BINARY
    void AVoiceRecordTest::StopAndSaveRecording(FString SaveFilePath)
    {
        StartRecord = false;
        if (VoiceCapture.Get() != NULL)
        {
            VoiceCapture->Stop();
            UE_LOG(LogTemp, Warning, TEXT("Stopped Recording"));
    
            //SAVING THE DATA IN BINARY
            FBufferArchive  ToBinary;
            ToBinary << VoiceCaptureBufferAppended;
    
            const TCHAR* PathString = *SaveFilePath;
    
            if (FFileHelper::SaveArrayToFile(ToBinary, PathString))
            {
                ToBinary.FlushCache();
                ToBinary.Empty();
            }
    
            ToBinary.FlushCache();
            ToBinary.Empty();
    
            UE_LOG(LogTemp, Warning, TEXT("File Saved"));
        }
    
        else
        {
            UE_LOG(LogTemp, Warning, TEXT("Microphone Not Plugged In"));
        }
    
    
    }


    //LOAD THE BINARY DATA IN GAME AND PLAY
    void AVoiceRecordTest::LoadFromBinaryAndPlay(FString SavedFilePath)
    {
        //loading from file to binary array
        const TCHAR* PathString = *SavedFilePath;
        FFileHelper::LoadFileToArray(DataTakenFromBinary, PathString);
        
        //converting from binary array to required readable data
        TArray<uint8> Var;
        FMemoryReader Ar = FMemoryReader(DataTakenFromBinary, true); //true, free data after done
        Ar.Seek(0); //make sure we are at the beginning
        Ar << Var;
        //VoiceCaptureAudioComponent->Stop();
        //queuing and playing below
        uint32 VoiceCaptureReadBytes;
        VoiceCaptureReadBytes = sizeof(uint8)*Var.Num();
        VoiceCaptureSoundWaveProcedural->CleanupCachedRunningPlatformData();
        VoiceCaptureSoundWaveProcedural->QueueAudio(Var.GetData(), VoiceCaptureReadBytes);
        VoiceCaptureAudioComponent->SetSound(VoiceCaptureSoundWaveProcedural);
        VoiceCaptureAudioComponent->Play();
        //SoundDuration = VoiceCaptureSoundWaveProcedural->GetDuration();
        if (VoiceCaptureAudioComponent->IsPlaying())
        {
            UE_LOG(LogTemp, Warning, TEXT("Playing File"));
        }
        else
        {
            UE_LOG(LogTemp, Warning, TEXT("Playing NOT File"));
        }
    }