Help us understand the problem. What is going on with this article?

UE4 サウンドデータ再生とAudioComponentについて

概要

UnrealEngine のサウンドデータ再生とオーディオコンポーネントについてのメモ書きです。

修正履歴

日付 内容
2019/09/18 SpawnSound2Dについて追記
2019/10/02 PlaySoundAtLocationについて修正
2019/10/21 wave以外のサウンドデータについて追記

環境

Windows10
Visual Studio 2017
UnrealEngine 4.22

参考

以下を参考にさせて頂きました、ありがとうございます。

公式 - Audioコンポーネント
公式 - UAudioComponent
UE4 Saitama 初心者向けハンズオン #7『サウンド機能』

サウンドデータアセット

再生する対象は主に以下2種です。

サウンドウェーブ

サウンドファイルをコンバートしたアセット。サンプリングレートは44.1kHz以下が必要です。
ループ設定やストリーミング設定は[詳細]から行います。

SoundWaveDetail.jpg

waveファイル自体にループポイント設定をしても反映はされないようです。
24bitや32bitのハイレゾ音源も不可だと思われます。

wave以外のサウンドデータについて

4.22から[AIFF], [FLAC], [Ogg Vorbis]も対応フォーマットとして追加されているようです。
- Aiff 2ch 16bit 8kHz
- Flac 1ch 16bit 8kHz
の2種を試してみましたが、特に問題なくUEエディタでサウンドウェーブアセットにコンバート&エディタにて再生できました。

サウンドキュー

サウンドデータに対し、合成やエフェクトやプロパティの変更をかけたものです。

SoundCue.jpg

サウンドデータ再生

サウンドの再生メソッドのまとめです。

PlaySound2D

2Dサウンドの再生、3D座標の影響はありません。

PlaySound2D.png

C++でサウンドウェーブを再生するテストコードです。
サウンドキューの場合も基底の USoundBaseクラスで受けているので同じコードになります。

ATestActor.h
UPROPERTY()
USoundBase* Sound_Obj;
ATestActor.cpp
// コンストラクタ
// se_ok というサウンドウェーブオブジェクトを探す
static ConstructorHelpers::FObjectFinder< USoundBase > find_sound(TEXT("SoundWave'/Game/Sound/se_ok.se_ok'"));
    if (find_sound.Succeeded()) {
        Sound_Obj = find_sound.Object;
    }

...

// 再生(7番目の引き数でオーナーアクターを自分に)
UGameplayStatics::PlaySound2D(GetWorld(), Sound_Obj, 1.0f, 1.0f, 0.0f, nullptr, this);

SpawnSound2D / CreateSound2D

2Dサウンドの再生、返り値にUAudioComponentを返します。
Createのほうは自動で再生しないため、AudioComponentでPlayする必要があります。

SpwanSound2D.png

.cpp
// 再生(8番目の引き数がtrueで自動削除)
UGameplayStatics::SpawnSound2D(GetWorld(), SoundObject, 1.0f, 1.0f, 0.0f, nullptr, false, false);

自動削除したオーディオコンポーネントに対しアクセスを行うとクラッシュするので注意が必要です。

PlaySoundAtLocation / SpawnSoundAtLocation

3Dサウンドの再生、音源の座標を指定する必要があります。音源の移動はしません。

SpawnSoundatLocation.png

C++でサウンドウェーブを再生するテストコードです。
サウンドウェーブの場合も基底の USoundBaseクラスで受けているので同じコードになります。

ATestActor.h
UPROPERTY()
USoundBase* Sound_Obj;
ATestActor.cpp
// コンストラクタ
// SoundCue_Test というサウンドキューオブジェクトを探す
static ConstructorHelpers::FObjectFinder< USoundBase > find_sound(TEXT("SoundCue'/Game/Sound/SoundCue_Test.SoundCue_Test'"));
    if (find_sound.Succeeded()) {
        Sound_Obj = find_sound.Object;
    }

...

// 再生
UGameplayStatics::PlaySoundAtLocation(GetWorld(), Sound_Obj, GetActorLocation());

// オーディオコンポーネントが必要な場合はこちら
// UAudioComponent* _Audio = UGameplayStatics::SpawnSoundAtLocation(GetWorld(), Sound_Obj, GetActorLocation());

SpawnSoundAttached

3Dサウンドの再生、アタッチするコンポーネントを指定する必要があります。
アタッチ後は音源位置がコンポーネント位置に更新されるようです。

SpawnSoundAttached.png

オーディオコンポーネント

サウンドデータを1つ再生管理できます。
途中で別のサウンドに差し替え(SetSound)もできますが、その場合前のサウンドは停止します。

コンポーネント設定詳細

Detail.png

詳細にデフォルトサウンドアセットを設定できますが、スポーン時に再生されてしまいます。それを回避するには[Auto Activate]を false にして、任意のタイミングでオーディオコンポーネントをアクティベートすればできます。

メソッド

オーディオコンポーネントの代表的なメソッドです。C++でのコードもアセットの指定以外ほとんどそのままです。

Play

サウンドを再生します。引き数でディレイ時間を指定できます。
Play.png

.cpp
// サウンド再生
AudioComponent->Play();

Stop

サウンドを停止します。
Stop.png

.cpp
// サウンド停止
AudioComponent->Stop();

IsPlaying

サウンドが再生中か調べます。
IsPlaying.png

.cpp
if(AudioComponent->IsPlaying()){
    // 再生中
}

SetSound

オーディオコンポーネントのサウンドアセットを差し替えます。

SetSound.png

.h
UPROPERTY()
USoundBase* SoundObject;
.cpp
// コンストラクタ
static ConstructorHelpers::FObjectFinder< USoundBase > find_sound(TEXT("SoundWave'/Game/Sound/test_se.test_se'"));
if (find_sound.Succeeded()) {
    SoundObject = find_sound.Object;
}

...

// サウンドアセット差し替え
AudioComponent->SetSound(SoundObject);

FadeIn / FadeOut

フェードの設定です。Play()/Stop()代わりに使用することができます。

FadeInOut.png

SetVolumeMultiplier

ボリュームの変更です。現在のボリューム値への掛け算で変更します。

SetVolumeMaltiplier.png

AdjustVolume

ボリュームの変更です。引き数で変化する時間を設定できます。

AdjustVolume.png

.cpp
// 1.0秒かけてボリューム値0へ変更
AudioComponent->AdjustVolume(1.0f, 0.0f);

SetPitchMultiplier

ピッチの変更です、現在のピッチへの乗算値で変更します。

SetPitchMultiplier.png

.cpp
// ピッチの変更
AudioComponent->SetPitchMultiplier(0.5f);

イベント

OnAudioFinished

オーディオ再生を最後まで再生したか、停止した時に呼ばれるイベント

OnAudioFinished.png

C++ではNative用のデリゲートが用意されています。
以下サンプルコード。

.h
UFUNCTION()
        void TestFinished(UAudioComponent* _AudioComponent){ UE_LOG(LogTemp, Log, TEXT("TestFinished!")); }
.cpp
// 取得したオーディオコンポーネントに対しイベントを登録
AudioComponent->OnAudioFinishedNative.AddUFunction(this, "TestFinished");

再生終了時に[TestFinished!]がアウトプットログに出力されます。

OnAudioPlaybackPercent

サウンドが再生されている間ずっと呼ばれるイベント
サウンドの再生時間を取得できます。

OnAudioPlaybackPercent.png

こちらもC++ではNative用のデリゲートが用意されています。
以下サンプルコード。

.h
UFUNCTION()
        void TestPercent(UAudioComponent* _AudioComponent, const class USoundWave* _SoundWave, const float _Per){
        UE_LOG(LogTemp, Log, TEXT("%f"), _Per);
    }
.cpp
// 取得したオーディオコンポーネントに対しイベントを登録
AudioComponent->OnAudioPlaybackPercentNative.AddUFunction(this, "TestPercent");

これで再生中にアウトプットログに再生時間が出力されます。

OnAudioSingleEnvelopeValue

サウンドのエンベロープ値(ボリューム値)を取得するイベント
サウンドキューの[Enveloper]適用時?

OnAudioSingleEnvelopeValue.png

OnAudioMultiEnvelopeValue

サウンドのエンベロープ値(ボリューム値)を取得するイベント
サウンドキューの[Enveloper]適用時?

OnAudioMultiEnvelopeValue.png

PhysicsVolumeChanged

PhysicsVolumeが変更されたときに呼ばれるイベント
変更後のボリューム値が取得できます。

PhysicsVolumeChanged.png

OnComponentActivated

AudioComponentがアクティブになった時に呼ばれるイベント

OnComponentActivated.png

OnComponentDeactivated

AudioComponentが非アクティブになった時に呼ばれるイベント

OnComponentDeactivated.png

C++でのアクターへのオーディオコンポーネントの追加

以下の様に追加できます。
細かい設定(サウンドクラスやサウンド減衰アセット)の指定がアセットファイルなため面倒です。

.h
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Test")
    class UAudioComponent* AudioComponent;
.cpp
// コンストラクタ
AudioComponent = CreateDefaultSubobject<UAudioComponent>(TEXT("AudioComponent0"));
if (AudioComponent) {
    AudioComponent->SetupAttachment(RootComponent);
    AudioComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 0.0f));
    AudioComponent->SetSound(NewSound);
}

アニメ―ションシーケンスでのサウンド再生について

AnimNotifySound

アニメ―ションシーケンスに対し、直接サウンドを再生する通知を追加できます。
[通知を追加] -> [Play Sound]
AddAnimNotifySound.jpg

このようにアニメ―ショントラックに通知が追加されています。
AnimNotifySound.png
サウンド再生のタイミングはアニメ―ションに紐づくものも多いのでこれで十分な場合も多いと思います。
また、アニメ―ションモンタージュにも通知の追加が可能です。

State版のAnimNotifySoundを作る場合の注意点

AnimNotifyStateのSound版はver.4.22時点は存在しませんが、UAnimNotifyState_TimedParticleEffectクラスを参考に作成することは可能だと思われます。
ただ、AnimNotifyクラスやAnimNotifyStateクラスはインスタンス毎に作成されるわけではなく、1つのオブジェクトを使いまわしするため、メンバ変数にそのまま情報を持つと別の通知で参照を行ったり書き換えたりするとバグります。
別途メンバに持たせる情報を管理するプールを用意するなどしないとなりませんので手間です。

まとめ

ループサウンドはアクターがAudioComponentを持って再生,停止を管理し、短いワンショットサウンドはSpawnSound等で再生し、長いワンショットサウンドはケースにより管理するかどうかを決める必要があると思います。

再生サウンド全体を一括管理するようなものはないんですかね。。:thinking:

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away