버전

menu_open
Wwise Unreal Integration Documentation
Providing Audio Input to Wwise

The Unreal integration provides audio input to Wwise through the Wwise Audio Input Source Plug-in. In order to provide audio input to Wwise, classes must inherit from AkAudioInputComponent.

AkAudioInputComponent

AkAudioInputComponentAkComponent 로부터 파생됩니다. It is a specialized AkComponent that you can use to provide audio input to Wwise. To do so, you must implement two key functions:

/* 오디오 호출. 이 함수는 Wwise 사운드 엔진에 의해 계속해서 호출되며
* 사운드 엔진에 오디오 샘플을 제공하는 데에 사용됩니다. */
virtual bool FillSamplesBuffer(uint32 NumChannels, uint32 NumSamples, float** BufferToFill);
/* 이 콜백은 Wwise 사운드 엔진에 필요한 오디오 형식을 제공하는 데에 사용됩니다. */
virtual void GetChannelConfig(AkAudioFormat& AudioFormat);

AkAudioInputComponent also has one Blueprint function, Post Associated Audio Input Event, which posts the component's AkAudioEvent to Wwise along with the associated AudioSamples callback and AudioFormat callback, using this component as the game object source.

Customizing Audio Input Behavior

You can write custom classes that derive from AkAudioInputComponent in order to implement custom audio input behavior. The following UAkVoiceInputComponent.h and UAkVoiceInputComponent.cpp examples show a class that takes microphone input and pipes it to the Wwise Sound Engine.

Before you can use these files in a C++ Unreal project, you must perform some initial setup. First, add the AkAudio and the Unreal Voice modules to the PublicDependencyModuleNames in the project's Build.cs file. 예시:

public class MyModule : ModuleRules
{
public MyModule(ReadOnlyTargetRules Target) : base(Target)
{
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "AkAudio", "Voice" });
// 그 외 설정
}
}

Next, add the following lines to the DefaultEngine.ini file:

[Voice]
bEnabled=true

After these setup steps are complete, add the desired custom behavior. In the following example, a class takes microphone input and sends it to Wwise.

참고:

The sample code in this section is not intended for use in shipped games. It is only a short example of how to implement custom behavior.

Here is an example of a customized AkVoiceInputComponent.h file:

#pragma once
#include "CoreMinimal.h"
#include "AkAudioInputComponent.h"
#include "Voice.h"
#include "AkVoiceInputComponent.generated.h"
/*
*/
UCLASS(ClassGroup = Audiokinetic, BlueprintType, hidecategories = (Transform, Rendering, Mobility, LOD, Component, Activation), meta = (BlueprintSpawnableComponent))
class WWISEDEMOGAME_API UAkVoiceInputComponent : public UAkAudioInputComponent
{
GENERATED_BODY()
UAkVoiceInputComponent(const class FObjectInitializer& ObjectInitializer);
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override;
protected:
/* 이 부분은 이 컴포넌트를 소유하는 GameObject가Wwise 사운드 엔진에서 등록 해제된 후에 호출됩니다. */
virtual void PostUnregisterGameObject() override;
/* 오디오 호출. 이 부분은 Wwise 사운드 엔진에 의해 지속적응로 호출되며
사운드 엔진에 오디오 샘플을 제공하는 데에 사용됩니다. */
virtual bool FillSamplesBuffer(uint32 NumChannels, uint32 NumSamples, float** BufferToFill) override;
/* 이 콜백은 Wwise 사운드 엔진에 필요한 오디오 형식을 제공하는 데에 사용됩니다. */
virtual void GetChannelConfig(AkAudioFormat& AudioFormat) override;
/* 마이크 입력에 접근하는 데에 사용되는 Unreal IVoiceCapture입니다. */
TSharedPtr<IVoiceCapture> VoiceCapture;
/* 이 배열은 보이스 캡처로부터 새로운 버퍼가 들어올 때마다 초기화되며 다시 채워집니다. */
TArray<uint8> IncomingRawVoiceData;
/* 이 배열은 보이스 캡처로부터 수집된 이던의 모든 오디오 데이터를 담습니다.
제공되는 마이크 데이터를 처리할 때 제작되며
Wwise 엔진에 데이터를 전달할 때 읽혀집니다 (그리고 축소됩니다).
오디오 콜백에서 버퍼를 축소하는 것은 권장하지 않으며 출시 게임에서는 사용하지 말아야 합니다!*/
TArray<uint8> CollectedRawVoiceData;
/* 이 플래그는 마이크 데이터를 읽는 동안 수집된 데이터 버퍼에 마이크 데이터를 제작하지 않도록 방지해줍니다. */
FThreadSafeBool bIsReadingVoiceData = false;
};

Here is an example of a customized AkVoiceInputComponent.cpp file:

#include "AkVoiceInputComponent.h"
UAkVoiceInputComponent::UAkVoiceInputComponent(const class FObjectInitializer& ObjectInitializer) :
UAkAudioInputComponent(ObjectInitializer)
{
CollectedRawVoiceData.Reset();
VoiceCapture = FVoiceModule::Get().CreateVoiceCapture();
}
void UAkVoiceInputComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if (!VoiceCapture.IsValid())
{
return;
}
uint32 NumAvailableVoiceCaptureBytes = 0;
EVoiceCaptureState::Type CaptureState = VoiceCapture->GetCaptureState(NumAvailableVoiceCaptureBytes);
/* IVoiceCapture는 각 틱마다 EVoiceCaptureState를 업데이트합니다.
그렇기 때문에 틱과 틱 사이에 이 명시문이 수집할 새로운 데이터가 실제로 있는지 알려줄 것임을 알 수 있습니다. */
if (CaptureState == EVoiceCaptureState::Ok && NumAvailableVoiceCaptureBytes > 0)
{
uint32 NumVoiceCaptureBytesReturned = 0;
IncomingRawVoiceData.Reset((int32)NumAvailableVoiceCaptureBytes);
IncomingRawVoiceData.AddDefaulted(NumAvailableVoiceCaptureBytes);
uint64 SampleCounter = 0;
VoiceCapture->GetVoiceData(IncomingRawVoiceData.GetData(), NumAvailableVoiceCaptureBytes, NumVoiceCaptureBytesReturned, SampleCounter);
if (NumVoiceCaptureBytesReturned > 0)
{
/* 수집된 버퍼에서 데이터를 읽는 동안 돌아갑니다 */
while (bIsReadingVoiceData) {}
CollectedRawVoiceData.Append(IncomingRawVoiceData);
}
}
}
bool UAkVoiceInputComponent::FillSamplesBuffer(uint32 NumChannels, uint32 NumSamples, float** BufferToFill)
{
if (!VoiceCapture.IsValid())
{
return false;
}
const uint8 NumBytesPerSample = 2;
const uint32 NumRequiredBytesPerChannel = NumSamples * NumBytesPerSample;
const uint32 NumRequiredBytes = NumRequiredBytesPerChannel * NumChannels;
int16 VoiceSample = 0;
uint32 RawChannelIndex = 0;
uint32 RawSampleIndex = 0;
bIsReadingVoiceData = true;
const int32 NumSamplesAvailable = CollectedRawVoiceData.Num() / NumBytesPerSample;
const uint32 BufferSlack = (uint32)FMath::Max(0, (int32)(NumSamples * NumChannels) - NumSamplesAvailable);
for (uint32 c = 0; c < NumChannels; ++c)
{
RawChannelIndex = c * NumRequiredBytesPerChannel;
for (uint32 s = 0; s < NumSamples; ++s)
{
if (s >= (NumSamples - BufferSlack) / NumChannels)
{
/* 보이스 캡처에서 받은 데이터가 Wwise 엔진에서 필요로 하는 데이터보다 적을 경우
누락된 샘플을 0으로 패딩합니다. */
BufferToFill[c][s] = 0.0f;
}
else
{
/* 전송되는 마이크 오디오 데이터를 부호가 있는 부동 소수점으로 변환합니다. */
uint32 RawSampleDataMSBIndex = s * 2 + 1;
uint32 RawSampleDataLSBIndex = s * 2;
VoiceSample = (CollectedRawVoiceData[RawSampleDataMSBIndex] << 8) | CollectedRawVoiceData[RawSampleDataLSBIndex];
BufferToFill[c][s] = VoiceSample / (float)INT16_MAX;
}
}
}
const int32 NumBytesRead = (NumSamples - BufferSlack) * NumBytesPerSample;
/* NOTE: 오디오 콜백에서 버퍼를 축소하는 것은 권장하지 않습니다. 출시 게임에서는 사용하지 마세요! */
CollectedRawVoiceData.RemoveAt(0, NumBytesRead);
bIsReadingVoiceData = false;
return true;
}
void UAkVoiceInputComponent::GetChannelConfig(AkAudioFormat& AudioFormat)
{
const int sampleRate = 16000;
AudioFormat.uSampleRate = sampleRate;
AudioFormat.channelConfig.SetStandard(AK_SPEAKER_SETUP_MONO);
if (VoiceCapture.IsValid())
{
/* 기본 장치에 빈 장치 이름을 전달합니다. */
if (!VoiceCapture->Init(FString(""), AudioFormat.uSampleRate, AudioFormat.channelConfig.uNumChannels))
{
UE_LOG(LogTemp, Error, TEXT("Failed to initialize device for voice input!"));
return;
}
VoiceCapture->Start();
}
}
void UAkVoiceInputComponent::PostUnregisterGameObject()
{
Super::PostUnregisterGameObject();
if (VoiceCapture.IsValid())
{
VoiceCapture->Stop();
VoiceCapture->Shutdown();
}
}

After you add the class to an Unreal project, you can create a custom Blueprint class that has an AkVoiceInputComponent, and can call the Post Associated Audio Input Event Blueprint function (from base class AkAudioInputComponent) to start sending microphone data to Wwise. The following image shows part of the Blueprint for a custom Blueprint class, based on Actor, that has an AkVoiceInputComponent called AkVoiceInput.


이 페이지가 도움이 되었나요?

지원이 필요하신가요?

질문이 있으신가요? 문제를 겪고 계신가요? 더 많은 정보가 필요하신가요? 저희에게 문의해주시면 도와드리겠습니다!

지원 페이지를 방문해 주세요

작업하는 프로젝트에 대해 알려주세요. 언제든지 도와드릴 준비가 되어 있습니다.

프로젝트를 등록하세요. 아무런 조건이나 의무 사항 없이 빠른 시작을 도와드리겠습니다.

Wwise를 시작해 보세요