サウンドの発音数制限をオブジェクト単位に分割する方法

発音数制御設定の影響範囲の分割

通常、1つのキャラクターが発するセリフなどのボイス音声は、同時に最大1音までしか再生されないようにデザインするのが自然です。
criware_ue4_035_chr_voice_explanation.png
上の図は、あるキャラクターの音声データである"VoiceA"と"VoiceB"を再生している図です。"VoiceA"の再生を始めた後に"VoiceB"の再生が始まっています。
しかし、点線で囲まれた範囲で"VoiceA"と"VoiceB"の再生が重なってしまっています。
1体のキャラクターが同時に複数の音声を発するのは不自然であるため、"VoiceA"が再生されているときには"VoiceB"の再生をできないように制御できると便利です。
この場合、サウンドデザイナーは CRI Atom Craft を用いて発音数制御の設定を行う必要があります。
CRI Atom Craft では以下のような発音数制御設定を行うことができます。
  • キューリミット
  • カテゴリリミット
  • ボイスリミット
本稿では各設定の詳細説明は割愛します。詳細については ADX2 ツールマニュアルを別途参照してください。
ここでは、対戦格闘ゲームのようなタイトルを想定して、同一キャラクターが同じシーン上に存在するケースを考えます。
また、キャラクターの発するボイス用キュー "VoiceA" には何かしらの発音数制御の設定が予め適用されていると仮定します。
現状では、これらの同一キャラクターのどちらか一方しか "VoiceA" を発音できません。
ゲームのデザイン上、これらの同一キャラクターたちが "VoiceA" を同時に再生できるようにしたいとします。
criware_ue4_035_sound_object_purpose.png
このようなデザインを実現する機能が "サウンドオブジェクト" です。
本ページではサウンドオブジェクト機能の使い方について説明します。

サウンドオブジェクトとは?

サウンドオブジェクトとは、各アクタごとに発音数制限を行うことを可能にするための機能です。
例えば、ゲーム内に「ジョン」というキャラクターがいて、色違いの「ジョンA」と「ジョンB」が同シーンに出てくる場面を考えてみましょう。
「ジョン」の音声データとして、AtomCraftで "dialogue_Hello" と "dialogue_Bye" という2つのキューを作成します。
カテゴリリミットでこれらの音声データは同時に1音までしか鳴らないように設定します。
これら2つのキューに対して、「ジョンA」が話すためのAtomコンポーネントと「ジョンB」が話すためのAtomコンポーネントを別々に用意します。
計4つのAtomコンポーネントを生成し、それぞれのAtomコンポーネントにキューをセットします。
criware_ue4_035_set_sound_to_atomcomponent.png

これら4つのAtomコンポーネントを同時間帯に重なるように再生させようとすると、最も最初に音を鳴らし始めたAtomコンポーネントが終了するまで他のAtomコンポーネントは再生を制限されます。
すると同シーンに登場している「ジョンB」は「ジョンA」が話し終わるまで何も話せなくなってしまいます。

criware_ue4_035_failed_case_for_playing_sound.png

そこでサウンドオブジェクトを用いて発音数制限のかける範囲をアクタ単位にします。
「ジョンA」に対応するサウンドオブジェクト(SoundObject_A)と「ジョンB」に対応するサウンドオブジェクト(SoundObject_B)を用意し、それぞれのキャラクターのAtomコンポーネントにセットします。

criware_ue4_035_set_soundobject_to_atomcomponent.png

するとカテゴリリミットのかかる範囲は同じサウンドオブジェクトを持っているAtomコンポーネント群のみに絞られます。
これで「同一キャラクターたちを同時に話させる」「1体のキャラクターは別の音声を同時には話さない」を実現することができます。

criware_ue4_035_success_case_for_playing_sound.png

このように、サウンドオブジェクトは発音数制限を行う範囲をさらに絞ることでアクタ単位での発音数制限を可能にするのです。

サウンドオブジェクトの適用方法

サウンドオブジェクトをAtomコンポーネントにセットして適用するためには、アクタ(アニメーションを持つときはSkeletalMeshアクタ)の下にAtom Parameterコンポーネントを用意しておき、そこにサウンドオブジェクトを予め持たせておきます。
すると、アクタのアニメーションが始まるなどしてAtomコンポーネントが生成された時に自動的にサウンドオブジェクトがAtomコンポーネントにセットされます。
criware_ue4_035_sound_object_specification1.png

アニメーションなどを介さずにAtomコンポーネントが再生される場合も同様に、Atom Parameterコンポーネントにサウンドオブジェクトを持たせておくことで自動的にAtomコンポーネントにサウンドオブジェクトがセットされます。

criware_ue4_035_sound_object_specification2.png

補足

アクタ単位ではなく、より柔軟にサウンドオブジェクトを使用したい場合はAtom Parameterコンポーネントを使用せずに直接Atomコンポーネントにサウンドオブジェクトをセットすることができます。
この場合はUAtomComponent::SetSoundObject関数を使用します。引数にはサウンドオブジェクトを指定します。

criware_ue4_035_directly_set_soundobject_to_atomcomponent.png

設定手順

サウンドオブジェクトを作成し、Atom Parameterコンポーネントにサウンドオブジェクトを持たせるまでの具体的な手順を説明していきます。

サウンドオブジェクトを作成する方法には「プログラム内で動的にサウンドオブジェクトを作成する」やり方と「コンテンツブラウザ内で予めサウンドオブジェクトを作成しておく」やり方の2通りがあります。

一度に大量の同一キャラクターが出現するような場合、個体数分だけそれぞれのサウンドオブジェクトを手動で設定するのはとても面倒です。そのような場合には前者のやり方でアクタごとに自動でサウンドオブジェクトが作成されるようにします。
一方、同一キャラクターがそれほど多く一度に登場しないような場合(例えばボスキャラなど)にはコンテンツブラウザ上で予めサウンドオブジェクトを作成しておく後者のやり方のほうが手っ取り早いです。

2通りの方法についてそれぞれご紹介します。

(注:使用するAtom CueアセットにはCRI AtomCraftで予めカテゴリリミットなどの発音数制御を設定しておいてください。)

プログラム内で動的にサウンドオブジェクトを作成する手順

1.発音数を制御したいAtom Cueアセットエディタを開いて、[Apply Atom Parameter]をONに設定しておきます。

criware_ue4_035_enable_apply_atom_parameter.jpg

2.アクタを選択し、[+コンポーネントを追加]メニューから[Atom Parameter]を追加します。

criware_ue4_035_add_atom_parameter_component1.jpg

3.Blueprintで下図のように記述することで、アクタ生成に合わせて動的にサウンドオブジェクトを生成してAtom Parameterコンポーネントにセットすることができます。

criware_ue4_035_construct_sound_object.png

4.[Enable Category Cue Limit Scope]のチェック欄と[Enable Voice Limit Scopt]のチェック欄はそれぞれAtomCraftで設定した「カテゴリ」・「ボイスリミットグループ」に対応しています。

SoundObject AtomCraft
Enable Category Cue Limit Scope カテゴリ
Enable Voice Limit Scope ボイスリミットグループ


\attention [Enable Category Cue Limit Scope]のチェック欄と[Enable Voice Limit Scopt]のチェック欄を、両方ともfalseの状態とした場合、サウンドオブジェクトを適用しないボイスに対して発音数が制御されるようになります。

カテゴリでキューリミットを設定している場合は[Enable Category Cue Limit Scope]をONに、ボイスリミットグループを設定している場合は[Enable Voice Limit Scopt]をONに設定します。

criware_ue4_035_explanation_of_soundobject_parameter.png

5.コンパイルし、プレイしてみます。
複数のアクタが同時に発音でき、かつ1体のアクタに発音数制限がかかっていることを確認出来たら設定完了です。

コンテンツブラウザ内で予めサウンドオブジェクトを作成する手順

1.アクタでキューを再生した際にサウンドオブジェクトを適用したいAtom Cueアセットエディタを開いて、[Apply Atom Parameter]をONに設定しておきます。
criware_ue4_035_enable_apply_atom_parameter.jpg

2.コンテンツブラウザ上で右クリックし、[その他]→[データアセット]を選択します。

criware_ue4_035_create_dataasset_in_contents_brouser.jpg

3.[AtomSoundObject]クラスを選択し、アセット名をつけます。

criware_ue4_035_select_sound_object.jpg

4.3で作成したデータアセットのエディタを開き、[Config]の[Enable Category Cue Limit Scope]と[Enable Voide Limit Scope]をAtomCraftの設定に合わせてONにします。

criware_ue4_035_enable_soundobject_parameter.jpg

5.アクタを選択し、[+コンポーネントを追加]メニューから[Atom Parameter]を追加します。

criware_ue4_035_add_atom_parameter_component2.jpg

6.作成された[Atom Parameter]コンポーネントのプロパティを編集し、[Sound Object]を指定します。

criware_ue4_035_set_soundobject_asset.jpg

cppによるSoundObjectの制御例

SoundObjectのAtomComponentへの適用をCPPから行いたい場合、UAtomComponent::SetSoundObject関数を使用します。
引数にはサウンドオブジェクトを指定します。

サウンドオブジェクトを動的に作成し、設定する例

例えば次々とスポーンする雑魚キャラにそれぞれ別々のサウンドオブジェクトを設定したい場合、雑魚キャラのスポーンに合わせて動的にサウンドオブジェクトを生成する必要があります。
今回は新規C++クラス(アクターを継承した雑魚キャラクラス)を作成し、そのクラスにAtomComponentを持たせ、そこに動的に生成したサウンドオブジェクトを設定する方法を解説します。
手順は以下の通りです。
  1. "CriWareApi.h", "AtomComponent.h", "AtomSoundObject.h" をインクルード
  2. メンバ変数としてUAtomComponent*型変数を持つ
  3. CreateDefaultSubobject又はNewObject関数を使用してUAtomSoundObjectのオブジェクトを作成
  4. 作成したサウンドオブジェクトのメンバ変数EnableCategoryCueLimitScopeやEnableVoiceLimitScopeを用途に応じてtrueに設定
  5. UAtomComponent*型変数のSetSoundObjectメンバ関数を使用してサウンドオブジェクトを設定
ソースコードは以下のようになります。
MyActor.h
#pragma once
// 1."CriWareApi.h", "AtomComponent.h", "AtomSoundObject.h" をインクルード
#include "CriWareApi.h"
#include "AtomComponent.h"
#include "AtomSoundObject.h"
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"
UCLASS()
class SO_PROJECTED_API AMyActor : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AMyActor();
public:
// 2.メンバ変数としてUAtomComponent*型変数を持つ
UAtomComponent * AtomExPlayer;
};
MyActor.cpp
#include "MyActor.h"
// Sets default values
AMyActor::AMyActor()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
AtomExPlayer = CreateDefaultSubobject<UAtomComponent>(TEXT("UAtomComponent1"));
AtomExPlayer->bEnableMultipleSoundPlayback = true;
AtomExPlayer->SetupAttachment(RootComponent);
// 3.CreateDefaultSubobject又はNewObject関数を使用してUAtomSoundObjectのオブジェクトを作成
UAtomSoundObject * SoundObject = CreateDefaultSubobject<UAtomSoundObject>(TEXT("UAtomSoundObject"));
// 4.作成したサウンドオブジェクトのメンバ変数EnableCategoryCueLimitScopeやEnableVoiceLimitScopeを用途に応じてtrueに設定
SoundObject->EnableCategoryCueLimitScope = true;
// 5.UAtomComponent*型変数のSetSoundObjectメンバ関数を使用してサウンドオブジェクトを設定
AtomExPlayer->SetSoundObject(SoundObject);
}