Skip to main content

DirectXTKとAudio

Step 00 DirectXTK Audio の基本

この回の目的

この回では、DirectXTK Audio で使う基本的なクラスの役割を整理します。

音を鳴らすプログラムでは、いきなりコードを書く前に、次の3つを分けて考えることが大切です。

AudioEngine           … 音を鳴らす仕組み全体
SoundEffect           … 音声ファイル1個分のデータ
SoundEffectInstance   … 実際に再生中の音

この3つの違いが分かると、DirectXTK Audio のコードがかなり読みやすくなります。


1. DirectXTK Audio で音を鳴らす流れ

DirectXTK Audio では、おおまかに次の流れで音を鳴らします。

AudioEngine を作る
↓
SoundEffect で wav ファイルを読み込む
↓
SoundEffect::Play() で音を鳴らす

一番単純な考え方は、これです。

AudioEngine  … 音を鳴らす機械本体
SoundEffect  … wav ファイルを読み込んだ音の素材
Play()       … その音を鳴らす命令

2. AudioEngine

AudioEngine は、DirectXTK Audio の中心になるクラスです。

std::unique_ptr<DirectX::AudioEngine> audioEngine_;

AudioEngine は、音を鳴らすための仕組み全体を管理します。

簡単に言うと、

AudioEngine = 音を鳴らす機械本体

です。

これがないと、音声ファイルを読み込んでも音を鳴らすことができません。


3. SoundEffect

SoundEffect は、音声ファイル1個分のデータを表します。

std::unique_ptr<DirectX::SoundEffect> sound_;

例えば、次のような音声ファイルを読み込んだものです。

shot.wav
jump.wav
damage.wav

実際のコードでは、次のように作ります。

sound_ = std::make_unique<DirectX::SoundEffect>(
    audioEngine_.get(),
    L"Assets/Audio/shot.wav"
);

イメージとしては、

SoundEffect = 音の素材

です。

短い効果音であれば、SoundEffectPlay() を呼ぶだけで再生できます。

sound_->Play();

4. SoundEffectInstance

SoundEffectInstance は、実際に再生中の音を表します。

std::unique_ptr<DirectX::SoundEffectInstance> instance_;

SoundEffectInstance は、SoundEffect から作ります。

instance_ = sound_->CreateInstance();

イメージとしては、次のようになります。

SoundEffect         = 音の素材
SoundEffectInstance = 実際に鳴っている音

例えば、engine.wav というエンジン音があったとします。

engine.wav

これは音の素材なので、SoundEffect として読み込みます。

その音を実際に鳴らしながら、あとから音量を変えたり、止めたり、ループさせたりしたい場合は、SoundEffectInstance を使います。

instance_->Play(true);
instance_->SetVolume(0.5f);
instance_->Stop();

5. SoundEffect と SoundEffectInstance の違い

ここが一番大切です。

クラス 役割 向いている使い方
SoundEffect 音声ファイルのデータ 短いSEを鳴らす
SoundEffectInstance 再生中の音 BGM、ループ音、音量変更、停止、一時停止

6. 短い効果音なら SoundEffect::Play()

例えば、弾を撃つ音です。

shotSound_->Play();

これは、

鳴らす
↓
終わったら自動で終わる

という使い方です。

この方法に向いている音は、次のようなものです。

ジャンプ音
攻撃音
決定音
ダメージ音
爆発音

何度も重なって鳴ってもよい音に向いています。


7. 止めたり音量を変えたいなら SoundEffectInstance

例えば、BGMです。

bgmInstance_ = bgmSound_->CreateInstance();
bgmInstance_->Play(true);

BGMは、あとから操作したくなることが多いです。

bgmInstance_->SetVolume(0.5f);
bgmInstance_->Pause();
bgmInstance_->Resume();
bgmInstance_->Stop();

この方法に向いている音は、次のようなものです。

BGM
足音ループ
エンジン音
環境音
3D空間で鳴らす音

8. たとえで考える

次のように考えると分かりやすいです。

AudioEngine
→ 音を鳴らすゲーム機本体

SoundEffect
→ wav ファイルを読み込んだ音の素材

SoundEffectInstance
→ 今、実際に鳴っている音

または、音楽プレイヤーにたとえると、こうなります。

AudioEngine
→ 音楽プレイヤー本体

SoundEffect
→ 音楽ファイル

SoundEffectInstance
→ 実際に再生中の曲

9. なぜ SoundEffect だけではだめなのか

短い効果音だけなら、SoundEffect::Play() で十分です。

shotSound_->Play();

しかし、次のようなことをしたい場合は、SoundEffect だけでは扱いにくくなります。

ループさせたい
途中で止めたい
一時停止したい
再開したい
音量を少しずつ変えたい
3D空間の位置を反映したい

このような場合は、SoundEffectInstance を使います。


10. SoundEffectInstance を使うときの注意

SoundEffectInstance は、元になった SoundEffect の音データを使います。

つまり、次のような関係です。

SoundEffect
  └─ SoundEffectInstance

そのため、SoundEffectInstance を使っている間に、元の SoundEffect を先に消してはいけません。

危険な順番はこれです。

SoundEffect を先に消す
↓
SoundEffectInstance が使う音データがなくなる
↓
正しく動かない可能性がある

安全な考え方は、次の順番です。

作る順番
AudioEngine
↓
SoundEffect
↓
SoundEffectInstance

消す順番
SoundEffectInstance
↓
SoundEffect
↓
AudioEngine

11. 今回作るオーディオエンジンでの使い分け

今回のオーディオエンジンでは、次のように使い分けます。

SE

SEは SoundEffect を使います。

Audio::LoadSE("shot", shotPath);
Audio::PlaySE("shot");

内部では、次のような処理になります。

sounds_["shot"]->Play();

SEは短く、鳴らしたら終わるものが多いからです。


BGM

BGMは SoundEffectInstance を使います。

Audio::LoadBGM("stage", bgmPath);
Audio::PlayBGM("stage", true);
Audio::StopBGM();

内部では、次のような処理になります。

bgmInstance_ = bgmSound_->CreateInstance();
bgmInstance_->Play(true);

BGMはループさせたり、止めたり、音量を変えたりしたいからです。


12. 最初に覚えること

最初は、これだけ覚えれば大丈夫です。

AudioEngine は、音を鳴らす仕組み本体。

SoundEffect は、wav ファイルを読み込んだ音データ。

SoundEffectInstance は、再生中の音を操作するためのもの。

使い分けは、次のように考えます。

短いSE
→ SoundEffect::Play()

BGM、ループ音、3D音、音量操作したい音
→ SoundEffectInstance

確認問題

問題1

AudioEngine は何をするためのクラスですか。

答え:

問題2

SoundEffect は何を表しますか。

答え:

問題3

BGMのように、ループさせたり止めたりしたい音には、SoundEffectSoundEffectInstance のどちらを使うとよいですか。

答え:

問題4

短いジャンプ音を1回鳴らすだけなら、次のどちらが向いていますか。

A. SoundEffect::Play()
B. SoundEffectInstance を作って管理する
答え: