--/--/--前の記事でかなり投げっぱなしだったXAPOの説明をします。Processing)のことです。音にかけるエフェクトを作る機構と思えば良いでしょう。今回はSampleAPOBase.hを利用しないで、自分で書いてみます。シンプルなソースです。入力された音のボリュームを小さくして出力しているだけです。パラメータが外部から入力されない場合は、CXAPOBaseを継承したクラスを作ります。DirectXSDKのマニュアルにある通り、CXAPOBaseはIXAPOの内、IXAPO::Process以外が実装されています。Processを実装すれば最低限の事はできます。ちなみにエフェクト本体はこのProcessに記述します。これだけでは入力に関する情報が分からないので、IXAPO::LockForProcessもオーバーライドしておきます。ついでにUnlockForProcessもオーバーライドしておくと、LockForProcessで初期化、UnlockForProcessで終了処理を書くことができます。LockForProcessの引数で、入力されるWavの形式がWAVEFORMATEXで渡されます。WAVEFORMATEXの中で特に重要なのは、チャンネル数を表すnChannelsです。ステレオの場合、nChannels=2ですね。入力されたフレーム数ValidFrameCountとwaveデータpBufferが渡されます。pBufferはfloat型の音声データで±1に正規化され(多分...)、チャンネル毎のデータが順番に(ステレオの場合、LRLRLR...)入っています(多分...)。)のデータが入っている訳です。pBufferは入力であると同時に出力でもあるので、ここに入っているデータを書き換えるとそのまま出力に反映されます。それでは、少しコードを書き換えてスペクトルアナライザを作ってみましょう。スペアナを実現するには、音声データにFFTをかければ良いのですが、そこそこの長さのデータが必要になます。4096個程度あれば十分でしょう。ValidFrameCountをこちらでコントロールする方法が無い(多分...)ので、自分でデータをバッファリングします。WAVEFORMATEXのnSamplesPerSecに書いてあるサンプリングレートを使えば、FFTの結果を実際の周波数に読み替えることができます。面倒なので、FFTの窓関数は矩形窓です。コンソール画面の8個の数字は、0Hzから12kHzまで1.5kHz刻みの音量をdb表記で示しています。鳴っている音は、125Hz、250Hz、500Hz、1000Hz、2000Hz、4000Hz、8000Hzのサイン波です。125〜1000Hzまでは一つ目の数字が、2000Hzでは2つ目の数字が、4000Hzでは3つ目の数字が、8000Hzでは6つ目の数字が、-13db程度の値で最大値になります。いつものことながら、エラーチェックは最低限であり、このサンプルの使用によるいかなる不幸も当方では責任を負いかねます。--/--/--ひさびさの新記事は、またOggVorbisネタです。ねぎしょ〜ぎのソースをコピペしただけって事は秘密です。SDKではDirectMusicのコンポーネントが入っていません。SDKまでしか対応していなかったようです。Vistaでは事実上DirectSoundの切捨てを行ったので、これを後生大事に使い続けるのも面白くありません。ここいらで新しいSoundAPIに乗り換えるのが吉でしょう。野村XXが乗り換えたのは、2008年夏だったのですが、実はその前からDirectMusicの代替物を探していました。ところが、OpenAL、XACT、XAudioと次世代のAPIがいくつかつばぜり合いを繰り広げていて、どれが標準になるのか分からない状況でした。そんな中で、XAudio2が2008年3月にリリースされ、(個人的には)決着がついたと思っています。機能的にはDirectSoundを置き換えるもので、DirectMusicのような高級なAPIではありません。Wav形式を始めとする各種音楽ファイルの読み込みやMIDIの再生などはサポートされていません。生のWaveデータがストリーミング再生できる機構にGPUのシェーダに近い、エフェクト機構がくっついたものです。実にシンプルな設計で好感が持てます。XPとVistaとXBoxのサウンド周りの違いをXAudio2が吸収し、その上にXACT3が乗っかっている形になります。概要はこちらのサイト(英語)を見ると分かりやすいかと。XAudio2はSourceVoiceとSubmixVoiceとMasteringVoiceから出来ています。SourceVoiceはWaveデータが置いてあるメモリ領域+それに付随するデータ(音量やピッチ)と考えれば良いでしょう。このSourceVoiceに対してエフェクトをかける機構がxAPOと呼ばれるものです。複数のSourceVoiceをミックスするのが、SubmixVoiceです。SourceVoiceの入力が生のWaveデータであるのに対し、SubmixVoiceはSourceVoiceの出力が入力になるというだけの違いです。MasteringVoiceは、複数のSourceVoiceとSubmixVoiceを一つにまとめて、スピーカーに送ります。要は、これら3つの要素がツリー状に繋がっている訳です。シンプルなプログラムは、以下の通りです。4のPCMデータ書き込みの所で、Waveファイルから読み込むかOggVorbisから読み込むか、はたまた別のファイルフォーマットを読み込むかは用途次第です。今回はWaveフォーマットはXAudioWave::Loadの中で地道に解析しています。OggVorbisについてはlibVorbis内のov_readを使っています。後の処理はWaveの再生と同じです。実際には、変換時間やメモリの使用量を考えるとストリーミング再生させるのが現実的でしょう。XAudio2はストリーミング再生が元からサポートされているので、この辺はシンプルに実装できます。一つのSourceVoiceに対し、複数回SubmitSourceBufferを実行することで、バッファリングが行われます。一つのバッファの再生が終わるとSetCallback_BufferEndで設定されたコールバック関数が呼び出されるので、そのバッファに続きのデータを書き込むだけです。これで最低限音を鳴らすことが出来るのですが、ゲーム用途を考えるとフェード機能くらいはあっても良いかと思います。そこで、xAPOをつかってフェードを実現します。XAPOのセットアップは少しややこしいので、MS謹製のヘルパークラスのSampleAPOBase.hを利用します。SampleAPOBaseを継承したクラスのInitに初期化、DoProcessにエフェクトのコードを書き込みます。DoProcessの引数で自由なパラメータを渡すことが出来るので、フェードのパラメータはこれを使ってxAPOに設定します。この辺はソースを実際に見た方が早いでしょう。いうわけで、今回のソースです。いつものことながら、エラーチェックは最低限であり、このサンプルの使用によるいかなる不幸も当方では責任を負いかねます。