XAudio2を使ってみる。その2-音の再生-
音データを格納する「バッファ」と、音源となる「ソース」を作成し、音の再生を行います。
バッファの作成
音データのフォーマットはWAVEFORMATEX構造体で記述します。設定するメンバは「チャンネル数」「1サンプルあたりのビット数」「サンプリング周波数」の3つです。その他のメンバは計算で求めることが可能です。
WAVEFORMATEX format = { 0 }; format.wFormatTag = WAVE_FORMAT_PCM; format.nChannels = 1; //チャンネル数 format.wBitsPerSample = 16; //1サンプルあたりのビット数 format.nSamplesPerSec = 44100; //サンプリングレート format.nBlockAlign = format.wBitsPerSample / 8 * format.nChannels; format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; //1秒分のバッファ std::vector< char > data( format.nAvgBytesPerSec * 1 );
- nChannels
- チャンネル数を指定。
- 1:モノラル
- 2:ステレオ
- チャンネル数を指定。
- wBitsPerSample
- 1サンプルあたりのビット数を指定。
- 8:128を無音とする0〜255の値を使用する
- 16:0を無音とする-32768〜32767の値を使用する
- 1サンプルあたりのビット数を指定。
- nSamplesPerSec
- サンプリングレート。1秒があたりのサンプル数
- サンプリング周波数 - Wikipedia
- 今回の例ではCDと同じ44100Hz
- サンプリングレート。1秒があたりのサンプル数
バッファにはWAVファイルから取得したデータをコピーする必要がありますが、今回はWAVファイルを使わずにプログラムで作った音を再生してみます。
作成する音はsin波の音階「ラ(A)」です。「ラ」は440Hzの周波数で表わされる音です。つまり1秒間に440回の波が必要になります。
44100Hzのバッファに440個の波を作るには、1つの波の波長が44100/440になります。
//ラを表すsin波(1秒) std::vector< char > data( format.nAvgBytesPerSec * 1 ); short* p = &data[ 0 ]; for( size_t i = 0; i < data.size() / 2; i ++ ) { float length = format.nSamplesPerSec / 440.0f; *p = ( short )( 32767 * sinf( i * 3.1415926535f / length ) ); p ++; }
SourceVoiceの作成
XAudioエンジンからWaveフォーマットを指定してSourceVoiceを作成します。
IXAudio2SourceVoice* source_voice;
HRESULT hr = xaudio->CreateSourceVoice( &source_voice, &format ); if( FAILED( hr ) ) throw "CreateSourceVoice";
XAUDIO2_BUFFER構造体を使ってバッファのバイト数、バッファの先頭アドレスを指定し、SourceVoiceにデータを送信します。(再生キューにデータを追加)
XAUDIO2_BUFFER buffer = { 0 }; buffer.AudioBytes = data.size(); //バッファのバイト数 buffer.pAudioData = ( BYTE* )&data[ 0 ]; //バッファの先頭アドレス buffer.Flags = XAUDIO2_END_OF_STREAM; // tell the source voice not to expect any data after this buffer source_voice->SubmitSourceBuffer( &buffer );
再生
SourceVoiceからStartメソッドを呼び出します。
source_voice->Start();
停止
再生カーソルを停止します。
source_voice->Stop();
SourcVoiceの破棄
source_voice->DestroyVoice();
全ソース
以下、1秒間「ラ」の音を再生するためのソースです。
#include <windows.h> #include <xaudio2.h> #include <vector> #include <cmath> #include <iostream> IXAudio2* xaudio; IXAudio2MasteringVoice* mastering_voice; IXAudio2SourceVoice* source_voice; void init() { // // Initialize XAudio2 // HRESULT hr; if( FAILED( hr = CoInitializeEx( NULL, COINIT_MULTITHREADED ) ) ) throw "CoInitializeEx"; UINT32 flags = 0; #ifdef _DEBUG flags |= XAUDIO2_DEBUG_ENGINE; #endif if( FAILED( hr = XAudio2Create( &xaudio, flags ) ) ) throw "XAudio2Create"; // // Create a mastering voice // if( FAILED( hr = xaudio->CreateMasteringVoice( &mastering_voice ) ) ) throw "CreateMasteringVoice"; } void cleanup() { // // Cleanup XAudio2 // if( mastering_voice != 0 ) { mastering_voice->DestroyVoice(); mastering_voice = 0; } if( xaudio != 0 ) { xaudio->Release(); xaudio = 0; } CoUninitialize(); } int main() { try { // // XAudioの初期化 // init(); HRESULT hr; // // Waveフォーマットの設定 // WAVEFORMATEX format = { 0 }; format.wFormatTag = WAVE_FORMAT_PCM; format.nChannels = 1; //チャンネル数 format.wBitsPerSample = 16; //1サンプルあたりのビット数 format.nSamplesPerSec = 44100; //サンプリング周波数 format.nBlockAlign = format.wBitsPerSample / 8 * format.nChannels; format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; // // SourceVoiceの作成 // if( FAILED( hr = xaudio->CreateSourceVoice( &source_voice, &format ) ) ) throw "CreateSourceVoice"; // // 適当な音を作成 // 「ラ」を表すsin波(440Hz、1秒) // std::vector< BYTE > data( format.nAvgBytesPerSec * 1 ); //バッファ short* p = ( short* )&data[ 0 ]; for( size_t i = 0; i < data.size() / 2; i ++ ) { float length = format.nSamplesPerSec / 440.0f; //波長 *p = ( short )( 32767 * sinf( i * 3.1415926535f / (length/2) ) ); p ++; } // // SourceVoiceにデータを送信 // XAUDIO2_BUFFER buffer = { 0 }; buffer.AudioBytes = data.size(); //バッファのバイト数 buffer.pAudioData = &data[ 0 ]; //バッファの先頭アドレス buffer.Flags = XAUDIO2_END_OF_STREAM; // tell the source voice not to expect any data after this buffer source_voice->SubmitSourceBuffer( &buffer ); // // 再生 // source_voice->Start(); MessageBox( 0, "終了します", "", 0 ); // // SourceVoiceの破棄 // source_voice->Stop(); source_voice->DestroyVoice(); } catch( const char* e ) { std::cout << e; } // // XAudioの破棄 // cleanup(); return 0; }
音階(平均律)
ちなみに、「ラ(A)」以外の音階は以下の周波数で表すことができます。
A | 440 |
A#, B♭ | 466.164 |
B, C♭ | 493.883 |
C, B# | 523.251 |
C#, D♭ | 554.365 |
D | 587.33 |
D#, E♭ | 622.254 |
E, F♭ | 659.255 |
F, E# | 698.457 |
F#, G♭ | 739.989 |
G | 783.991 |
G#, A♭ | 830.61 |
A | 880.000 |
これらの値は次の式で求めることができます。
float a[ 13 ]; for( int i = 0; i < 13; i ++ ) { float t = powf( 2.0f, 1.0f / 12 ); a[ i ] = 440.0f * powf( t, ( float )i ); }
サンプル
- xaudio2_02.zip
- VC++2008EE用
- DirectXSDK(Nobember2008)