注
このトピックは、DirectX チュートリアル シリーズを使用して簡単なユニバーサル Windows プラットフォーム (UWP) ゲームを作成する
このトピックでは、XAudio2 API
注
このサンプルの最新のゲーム コードをダウンロードしていない場合は、Direct3D サンプル ゲームに移動します。 このサンプルは、UWP 機能サンプルの大規模なコレクションの一部です。 サンプルをダウンロードする方法については、Windows 開発のサンプル アプリケーション
目的
XAudio2を使用してサンプル ゲームにサウンドを追加します。
オーディオ エンジンを定義する
サンプル ゲームでは、オーディオ オブジェクトと動作は次の 3 つのファイルで定義されます。
- Audio.h/.cpp: サウンド再生用の XAudio2 リソースを含む、Audio オブジェクトを定義します。 また、ゲームが一時停止または非アクティブ化された場合にオーディオ再生を中断および再開する方法も定義します。
- MediaReader.h/.cpp: ローカル ストレージからオーディオ .wav ファイルを読み取るためのメソッドを定義します。
- SoundEffect.h/.cpp: ゲーム内サウンド再生用のオブジェクトを定義します。
概要
ゲームへのオーディオ再生の設定には、主に 3 つの部分があります。
- オーディオ リソースを作成して初期化
- オーディオ ファイル を読み込む
- サウンドをオブジェクト に関連付ける
これらはすべて、Simple3DGame::Initialize メソッドで定義されています。 それでは、まずこのメソッドを調べてから、各セクションの詳細を見てみましょう。
設定後、サウンド エフェクトを再生する方法について説明します。 詳細については、にアクセスして、サウンドを再生してください。
Simple3DGame::Initialize メソッド
Simple3DGame::Initializeでは、m_controller と m_renderer も初期化され、オーディオ エンジンが設定され、サウンドを再生する準備が整います。
- m_audioControllerを作成します。これは、Audio クラスのインスタンスです。
- Audio::CreateDeviceIndependentResources メソッドを使用して、必要なオーディオ リソースを作成します。 ここでは、2 つの XAudio2 オブジェクト (音楽エンジン オブジェクトとサウンド エンジン オブジェクト)、およびそれぞれのマスタリング ボイスが作成されました。 音楽エンジン オブジェクトを使用して、ゲームのバックグラウンド ミュージックを再生できます。 サウンド エンジンは、ゲームでサウンド エフェクトを再生するために使用できます。 詳細については、「オーディオ リソースを作成して初期化する」を参照してください。
mediaReader を作成します。これは、MediaReader クラスのインスタンスです。 MediaReaderは、SoundEffect クラスのヘルパー クラスであり、ファイルの場所から小さなオーディオ ファイルを同期的に読み取り、サウンド データをバイト配列として返します。 - MediaReader::LoadMedia を使用して、その場所からサウンド ファイルを読み込み、読み込まれた.wavサウンド データを保持する targetHitSound 変数を作成します。 詳細については、「オーディオ ファイルを読み込む」を参照してください。
サウンド エフェクトはゲーム オブジェクトに関連付けられます。 そのため、そのゲーム オブジェクトとの衝突が発生すると、サウンド エフェクトが再生されます。 このサンプルゲームでは、弾薬(ターゲットを撃つために使用するもの)とターゲットのサウンドエフェクトがあります。
- GameObject クラスには、サウンドエフェクトをオブジェクトに関連付けるために使用される HitSound プロパティがあります。
- SoundEffect クラスの新しいインスタンスを作成し、初期化します。 初期化中に、サウンド エフェクトのソース 音声が作成されます。
- このクラスは、Audio クラスから提供されるマスタリング 音声を使用してサウンドを再生します。 サウンド データは、MediaReader クラスを使用してファイルの場所から読み取られます。 詳細については、「サウンドをオブジェクトに関連付ける」を参照してください。
注
サウンドを再生する実際のトリガーは、これらのゲーム オブジェクトの動きと衝突によって決まります。 そのため、これらのサウンドを実際に再生する呼び出しは、Simple3DGame::UpdateDynamics メソッドで定義されます。 詳細については、にアクセスして、サウンドを再生してください。
void Simple3DGame::Initialize(
_In_ std::shared_ptr<MoveLookController> const& controller,
_In_ std::shared_ptr<GameRenderer> const& renderer
)
{
// The following member is defined in the header file:
// Audio m_audioController;
...
// Create the audio resources needed.
// Two XAudio2 objects are created - one for music engine,
// the other for sound engine. A mastering voice is also
// created for each of the objects.
m_audioController.CreateDeviceIndependentResources();
m_ammo.resize(GameConstants::MaxAmmo);
...
// Create a media reader which is used to read audio files from its file ___location.
MediaReader mediaReader;
auto targetHitSoundX = mediaReader.LoadMedia(L"Assets\\hit.wav");
// Instantiate the targets for use in the game.
// Each target has a different initial position, size, and orientation.
// But share a common set of material properties.
for (int a = 1; a < GameConstants::MaxTargets; a++)
{
...
// Create a new sound effect object and associate it
// with the game object's (target) HitSound property.
target->HitSound(std::make_shared<SoundEffect>());
// Initialize the sound effect object with
// the sound effect engine, format of the audio wave, and audio data
// During initialization, source voice of this sound effect is also created.
target->HitSound()->Initialize(
m_audioController.SoundEffectEngine(),
mediaReader.GetOutputWaveFormatEx(),
targetHitSoundX
);
...
}
// Instantiate a set of spheres to be used as ammunition for the game
// and set the material properties of the spheres.
auto ammoHitSound = mediaReader.LoadMedia(L"Assets\\bounce.wav");
for (int a = 0; a < GameConstants::MaxAmmo; a++)
{
m_ammo[a] = std::make_shared<Sphere>();
m_ammo[a]->Radius(GameConstants::AmmoRadius);
m_ammo[a]->HitSound(std::make_shared<SoundEffect>());
m_ammo[a]->HitSound()->Initialize(
m_audioController.SoundEffectEngine(),
mediaReader.GetOutputWaveFormatEx(),
ammoHitSound
);
m_ammo[a]->Active(false);
m_renderObjects.push_back(m_ammo[a]);
}
...
}
オーディオ リソースを作成して初期化する
- XAudio2 API XAudio2Createを使用して、音楽と効果音エンジンを定義する 2 つの新しい XAudio2 オブジェクトを作成します。 このメソッドは、すべてのオーディオ エンジンの状態、オーディオ処理スレッド、音声グラフなどを管理する、オブジェクトの IXAudio2 インターフェイスへのポインターを返します。
- エンジンがインスタンス化されたら、IXAudio2::CreateMasteringVoice を使用して、サウンド エンジン オブジェクトごとにマスタリング ボイスを作成します。
詳細については、「方法: XAudio2を初期化する」を参照してください。
Audio::CreateDeviceIndependentResources メソッド
void Audio::CreateDeviceIndependentResources()
{
UINT32 flags = 0;
winrt::check_hresult(
XAudio2Create(m_musicEngine.put(), flags)
);
HRESULT hr = m_musicEngine->CreateMasteringVoice(&m_musicMasteringVoice);
if (FAILED(hr))
{
// Unable to create an audio device
m_audioAvailable = false;
return;
}
winrt::check_hresult(
XAudio2Create(m_soundEffectEngine.put(), flags)
);
winrt::check_hresult(
m_soundEffectEngine->CreateMasteringVoice(&m_soundEffectMasteringVoice)
);
m_audioAvailable = true;
}
オーディオ ファイルを読み込む
サンプル ゲームでは、オーディオ形式ファイルを読み取るためのコードは、MediaReader.h/cpp__ で定義されています。 エンコードされた.wavオーディオ ファイルを読み取るために、MediaReader::LoadMediaを呼び出し、.wavのファイル名を入力パラメーターとして渡します。
MediaReader::LoadMedia メソッド
このメソッドでは、Media Foundation API を使用して、.wav オーディオ ファイルをパルス コード変調 (PCM) バッファーとして読み取ります。
ソース リーダーを設定する
- MFCreateSourceReaderFromURL を使用して、メディア ソース リーダー (IMFSourceReader) を作成します。
- MFCreateMediaType
を使用して、メディアの種類 ( IMFMediaType ) オブジェクト (mediaType ) を作成します。 メディア形式の説明を表します。 mediaType デコードされた出力が PCM オーディオであることを指定します。これは、XAudio2使用できるオーディオの種類です。 - IMFSourceReader::SetCurrentMediaTypeを呼び出して、ソース リーダーのデコードされた出力メディアの種類を設定します。
ソース リーダーを使用する理由の詳細については、ソース リーダーを参照してください。
オーディオ ストリームのデータ形式について説明する
- IMFSourceReader::GetCurrentMediaType を使用して、ストリームの現在のメディアの種類を取得します。
- IMFMediaType::MFCreateWaveFormatExFromMFMediaType を使用して、以前の操作の結果を入力として使用して、現在のオーディオ メディアの種類を WAVEFORMATEX バッファーに変換します。 この構造体は、オーディオの読み込み後に使用されるウェーブ オーディオ ストリームのデータ形式を指定します。
WAVEFORMATEX 形式を使用して、PCM バッファーを記述できます。
WAVEFORMATEXTENSIBLE 構造体と比較して、オーディオウェーブ形式のサブセットのみを記述するために使用できます。
オーディオ ストリームの読み取り
- IMFSourceReader::GetPresentationAttribute
呼び出してオーディオ ストリームの期間を秒単位で取得し、期間をバイトに変換します。 - IMFSourceReader::ReadSample
呼び出して、オーディオ ファイルをストリームとして読み取ります。 readSample メディア ソースから次のサンプルを読み取ります。 - IMFSample::ConvertToContiguousBuffer を使用して、オーディオ サンプル バッファー (サンプル) の内容を配列 (mediaBuffer) にコピーします。
std::vector<byte> MediaReader::LoadMedia(_In_ winrt::hstring const& filename)
{
winrt::check_hresult(
MFStartup(MF_VERSION)
);
// Creates a media source reader.
winrt::com_ptr<IMFSourceReader> reader;
winrt::check_hresult(
MFCreateSourceReaderFromURL(
(m_installedLocationPath + filename).c_str(),
nullptr,
reader.put()
)
);
// Set the decoded output format as PCM.
// XAudio2 on Windows can process PCM and ADPCM-encoded buffers.
// When using MediaFoundation, this sample always decodes into PCM.
winrt::com_ptr<IMFMediaType> mediaType;
winrt::check_hresult(
MFCreateMediaType(mediaType.put())
);
// Define the major category of the media as audio. For more info about major media types,
// go to: https://msdn.microsoft.com/library/windows/desktop/aa367377.aspx
winrt::check_hresult(
mediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio)
);
// Define the sub-type of the media as uncompressed PCM audio. For more info about audio sub-types,
// go to: https://msdn.microsoft.com/library/windows/desktop/aa372553.aspx
winrt::check_hresult(
mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM)
);
// Sets the media type for a stream. This media type defines that format that the Source Reader
// produces as output. It can differ from the native format provided by the media source.
// For more info, go to https://msdn.microsoft.com/library/windows/desktop/dd374667.aspx
winrt::check_hresult(
reader->SetCurrentMediaType(static_cast<uint32_t>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), 0, mediaType.get())
);
// Get the current media type for the stream.
// For more info, go to:
// https://msdn.microsoft.com/library/windows/desktop/dd374660.aspx
winrt::com_ptr<IMFMediaType> outputMediaType;
winrt::check_hresult(
reader->GetCurrentMediaType(static_cast<uint32_t>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), outputMediaType.put())
);
// Converts the current media type into the WaveFormatEx buffer structure.
UINT32 size = 0;
WAVEFORMATEX* waveFormat;
winrt::check_hresult(
MFCreateWaveFormatExFromMFMediaType(outputMediaType.get(), &waveFormat, &size)
);
// Copies the waveFormat's block of memory to the starting address of the m_waveFormat variable in MediaReader.
// Then free the waveFormat memory block.
// For more info, go to https://msdn.microsoft.com/library/windows/desktop/aa366535.aspx and
// https://msdn.microsoft.com/library/windows/desktop/ms680722.aspx
CopyMemory(&m_waveFormat, waveFormat, sizeof(m_waveFormat));
CoTaskMemFree(waveFormat);
PROPVARIANT propVariant;
winrt::check_hresult(
reader->GetPresentationAttribute(static_cast<uint32_t>(MF_SOURCE_READER_MEDIASOURCE), MF_PD_DURATION, &propVariant)
);
// 'duration' is in 100ns units; convert to seconds, and round up
// to the nearest whole byte.
LONGLONG duration = propVariant.uhVal.QuadPart;
unsigned int maxStreamLengthInBytes =
static_cast<unsigned int>(
((duration * static_cast<ULONGLONG>(m_waveFormat.nAvgBytesPerSec)) + 10000000) /
10000000
);
std::vector<byte> fileData(maxStreamLengthInBytes);
winrt::com_ptr<IMFSample> sample;
winrt::com_ptr<IMFMediaBuffer> mediaBuffer;
DWORD flags = 0;
int positionInData = 0;
bool done = false;
while (!done)
{
// Read audio data.
...
}
return fileData;
}
サウンドをオブジェクトに関連付ける
オブジェクトへのサウンドの関連付けは、ゲームの初期化時に、Simple3DGame::Initialize メソッドで行われます。
要約:
- GameObject クラスには、サウンドエフェクトをオブジェクトに関連付けるために使用される HitSound プロパティがあります。
- SoundEffect クラス オブジェクトの新しいインスタンスを作成し、それをゲーム オブジェクトに関連付けます。 このクラスは、XAudio2 API を使用してサウンドを再生します。 Audio クラスによって提供されるマスタリング 音声を使用します。 サウンド データは、MediaReader クラスを使用してファイルの場所から読み取ることができます。
SoundEffect::Initialize は、次の入力パラメーターを使用して SoundEffect インスタンスを初期化するために使用されます。サウンド エンジン オブジェクトへのポインター(Audio::CreateDeviceIndependentResources メソッドで作成された IXAudio2 オブジェクト)、MediaReader::GetOutputWaveFormatExを使用した .wav ファイルの形式へのポインター、および MediaReader::LoadMedia メソッドを使用して読み込まれたサウンド データ。 初期化中に、サウンド エフェクトのソース 音声も作成されます。
SoundEffect::Initialize メソッド
void SoundEffect::Initialize(
_In_ IXAudio2* masteringEngine,
_In_ WAVEFORMATEX* sourceFormat,
_In_ std::vector<byte> const& soundData)
{
m_soundData = soundData;
if (masteringEngine == nullptr)
{
// Audio is not available so just return.
m_audioAvailable = false;
return;
}
// Create a source voice for this sound effect.
winrt::check_hresult(
masteringEngine->CreateSourceVoice(
&m_sourceVoice,
sourceFormat
)
);
m_audioAvailable = true;
}
サウンドを再生する
サウンド エフェクトを再生するトリガーは、Simple3DGame::UpdateDynamics メソッドで定義されます。これは、オブジェクトの移動が更新され、オブジェクト間の衝突が決定されるためです。
オブジェクト間の相互作用は大きく異なるため、ゲームオブジェクトのダイナミクスについてはここでは説明しません。 その実装を理解したい場合は、Simple3DGame::UpdateDynamics メソッド
衝突が発生すると、原則として、SoundEffect::PlaySoundを呼び出してサウンドエフェクトが再生されるようにトリガーします。 このメソッドは、現在再生中のすべてのサウンド エフェクトを停止し、目的のサウンド データでメモリ内バッファーをキューに入れます。 ソース音声を使用して音量を設定し、サウンド データを送信し、再生を開始します。
SoundEffect::PlaySound メソッド
- ソース音声オブジェクト m_sourceVoice を使用して、サウンド データ バッファーの再生を開始 m_soundData
- サウンド データ バッファーへの参照を提供する
XAUDIO2_BUFFER を作成し、IXAudio2SourceVoice::SubmitSourceBuffer呼び出して送信します。 - サウンドデータをキューに入れた状態で、SoundEffect::PlaySound が、IXAudio2SourceVoice::Startを呼び出して再生を開始します。
void SoundEffect::PlaySound(_In_ float volume)
{
XAUDIO2_BUFFER buffer = { 0 };
if (!m_audioAvailable)
{
// Audio is not available so just return.
return;
}
// Interrupt sound effect if it is currently playing.
winrt::check_hresult(
m_sourceVoice->Stop()
);
winrt::check_hresult(
m_sourceVoice->FlushSourceBuffers()
);
// Queue the memory buffer for playback and start the voice.
buffer.AudioBytes = (UINT32)m_soundData.size();
buffer.pAudioData = m_soundData.data();
buffer.Flags = XAUDIO2_END_OF_STREAM;
winrt::check_hresult(
m_sourceVoice->SetVolume(volume)
);
winrt::check_hresult(
m_sourceVoice->SubmitSourceBuffer(&buffer)
);
winrt::check_hresult(
m_sourceVoice->Start()
);
}
Simple3DGame::UpdateDynamics メソッド
Simple3DGame::UpdateDynamics メソッドは、ゲーム オブジェクト間の相互作用と競合を処理します。 オブジェクトが衝突 (または交差) すると、関連するサウンド エフェクトが再生されます。
void Simple3DGame::UpdateDynamics()
{
...
// Check for collisions between ammo.
#pragma region inter-ammo collision detection
if (m_ammoCount > 1)
{
...
// Check collision between instances One and Two.
...
if (distanceSquared < (GameConstants::AmmoSize * GameConstants::AmmoSize))
{
// The two ammo are intersecting.
...
// Start playing the sounds for the impact between the two balls.
m_ammo[one]->PlaySound(impact, m_player->Position());
m_ammo[two]->PlaySound(impact, m_player->Position());
}
}
#pragma endregion
#pragma region Ammo-Object intersections
// Check for intersections between the ammo and the other objects in the scene.
// ...
// Ball is in contact with Object.
// ...
// Make sure that the ball is actually headed towards the object. At grazing angles there
// could appear to be an impact when the ball is actually already hit and moving away.
if (impact > 0.0f)
{
...
// Play the sound associated with the Ammo hitting something.
m_objects[i]->PlaySound(impact, m_player->Position());
if (m_objects[i]->Target() && !m_objects[i]->Hit())
{
// The object is a target and isn't currently hit, so mark
// it as hit and play the sound associated with the impact.
m_objects[i]->Hit(true);
m_objects[i]->HitTime(timeTotal);
m_totalHits++;
m_objects[i]->PlaySound(impact, m_player->Position());
}
...
}
#pragma endregion
#pragma region Apply Gravity and world intersection
// Apply gravity and check for collision against enclosing volume.
...
if (position.z < limit)
{
// The ammo instance hit the a wall in the min Z direction.
// Align the ammo instance to the wall, invert the Z component of the velocity and
// play the impact sound.
position.z = limit;
m_ammo[i]->PlaySound(-velocity.z, m_player->Position());
velocity.z = -velocity.z * GameConstants::Physics::GroundRestitution;
}
...
#pragma endregion
}
次のステップ
Windows 10 ゲームの UWP フレームワーク、グラフィックス、コントロール、ユーザー インターフェイス、オーディオについて説明しました。 このチュートリアルの次の部分 サンプル ゲームの拡張に関するページでは、ゲームの開発時に使用できるその他のオプションについて説明します。
オーディオの概念
Windows 10 ゲーム開発の場合は、XAudio2 バージョン 2.9 を使用します。 このバージョンは Windows 10 に付属しています。 詳細については、「XAudio2 バージョン」を参照してください。
AudioX2 は、信号処理とミキシング基盤を提供する低レベルの API です。 詳細については、「XAudio2 の主要概念
XAudio2 ボイス
XAudio2 音声オブジェクトには、ソース、サブミックス、マスタリングボイスの 3 種類があります。 音声は、XAudio2 がオーディオ データの処理、操作、再生に使用するオブジェクトです。
- ソース音声は、クライアントによって提供されるオーディオ データに対して動作します。
- ソースボイスとサブミックスボイスは、その出力を1つ以上のサブミックスまたはマスタリングボイスに送信します。
- サブミックスとマスタリング音声は、それらを供給するすべての音声からのオーディオをミックスし、結果に基づいて動作します。
- マスタリングボイスは、ソースボイスとサブミックスボイスからデータを受信し、そのデータをオーディオハードウェアに送信します。
詳細については、XAudio2 音声をご確認ください。
オーディオ グラフ
オーディオ グラフは、XAudio2 音声
追加の参考資料
- 方法: XAudio2 を初期化する
- 方法: XAudio2 でオーディオ データ ファイルを読み込む
- 方法: XAudio2 でサウンドを再生する
キーオーディオの.hファイル
Audio.h
// Audio:
// This class uses XAudio2 to provide sound output. It creates two
// engines - one for music and the other for sound effects - each as
// a separate mastering voice.
// The SuspendAudio and ResumeAudio methods can be used to stop
// and start all audio playback.
class Audio
{
public:
Audio();
void Initialize();
void CreateDeviceIndependentResources();
IXAudio2* MusicEngine();
IXAudio2* SoundEffectEngine();
void SuspendAudio();
void ResumeAudio();
private:
...
};
MediaReader.h
// MediaReader:
// This is a helper class for the SoundEffect class. It reads small audio files
// synchronously from the package installed folder and returns sound data as a
// vector of bytes.
class MediaReader
{
public:
MediaReader();
std::vector<byte> LoadMedia(_In_ winrt::hstring const& filename);
WAVEFORMATEX* GetOutputWaveFormatEx();
private:
winrt::Windows::Storage::StorageFolder m_installedLocation{ nullptr };
winrt::hstring m_installedLocationPath;
WAVEFORMATEX m_waveFormat;
};
SoundEffect.h
// SoundEffect:
// This class plays a sound using XAudio2. It uses a mastering voice provided
// from the Audio class. The sound data can be read from disk using the MediaReader
// class.
class SoundEffect
{
public:
SoundEffect();
void Initialize(
_In_ IXAudio2* masteringEngine,
_In_ WAVEFORMATEX* sourceFormat,
_In_ std::vector<byte> const& soundData
);
void PlaySound(_In_ float volume);
private:
...
};