DirectXプログラミング講座 〜Vol11. 3D空間におけるサウンド処理〜

3Dプログラミングに欠かせない技術が3D空間におけるサウンド処理です。前後左右のスピーカー音量の調整及びドップラー効果を考慮したサウンド周波数の変化など、3D空間の中をあたかも音を発する物質が存在するかのような処理を体感してみましょう。


3Dサウンドの概要

通常のサウンド処理ならば、再生/停止などという簡単な制御ができればいいのですが、3Dサウンドでは、「音源」と「リスナー」という概念を理解しなければなりません。

音源とは

その名の通り、音を発する3D空間内の物質です。ここでいう物質とは、音だけに関するものであり、グラフィックスとして表示される類のものではありません。あくまで、音を発するだけにある擬似的な物質だということを理解しておきましょう。この音源はCAudio3Dクラス(CAudioの拡張クラス)を用いることで管理できます。音源は複数個存在させることができます。

リスナーとは

音源を3D空間のどの位置で、またどのような状況で聞き取るかといったことを管理するのが「リスナー」の役目です。リスナーはシステムに1つだけ存在し、複数の音源からの音を拾い集め、最終的にリスナーが聞こえた音がPCのスピーカーから鳴ることになります。

CAudio3Dクラス

エフェクト処理(SetEffectメンバ関数)を除いて、CAudioが提供する機能のすべてを利用することができます。今回はCAudio3Dクラスで追加される下の機能を利用します。

'最短距離を設定します。音源とリスナーとの距離が最短距離を超えると、サウンドは減衰していきます。
CAudio3D::SetMinDistance(
    distance As Single
) As Long

'最長距離を設定します。音源とリスナーとの距離が最長距離を超えると、音量は0になり、減衰のための計算はストップします。
CAudio3D::SetMaxDistance(
    distance As Single
) As Long

'音源の位置を設定します。
CAudio3D::SetPosition(
    x As Single,
    y As Single,
    z As Single
) As Long

'音源の速度を設定します。
CAudio3D::SetVelocity(
    x As Single,
    y As Single,
    z As Single
) As Long

CListenerクラス

リスナーの状況を管理するのがCListenerクラスです。

'リスナーの位置を設定します。
CAudio3D::SetPosition(
    x As Single,
    y As Single,
    z As Single
) As Long

'リスナーの速度を設定します。
CAudio3D::SetVelocity(
    x As Single,
    y As Single,
    z As Single
) As Long

'リスナーの頭部の向きを設定します。
CAudio3D::SetConeAngles(
    dwInsideAngle As DWord,
    dwOutsideAngle As DWord
) As Long

'3D空間におけるリスナー及び音源の状況を実際のパフォーマンス上で有効にします。
CAudio3D::CommitSettings() As Long

救急車が通り過ぎる音を再現するプログラム

プロジェクト名を "siren" にセットして、DirectXアプリケーションのプロジェクトを新たに作成します。ここから、siren.abpに対してコーディングをしていきます。

サンプルプロジェクトをダウンロード

●siren.abpの先頭部分のコーディング

CAudio3D及びCListenerオブジェクトポインタの定義を行います。また、救急車のZ軸上の位置を保持する変数CarZ、速度を保持する変数VelocityZを定義します。

MoveCarは救急車が走行する様子を再現するための関数です。新スレッドとして呼び出され、0.1秒間隔で速度に合わせた位置移動を行います。

#include "siren.idx"


Dim ScreenX=640 As Long    'ディスプレイの幅  (ピクセル単位)
Dim ScreenY=480 As Long    'ディスプレイの高さ(ピクセル単位)

' TODO: この位置にグローバル変数を定義してください。

Dim pListener As *CListener
Dim pAudio As *CAudio3D

'救急車のZ軸上の初期位置を原点からプラス100メートルの場所にセット
Dim CarZ=100 As Single

'救急車の速度を秒速15メートル(時速54キロ相当)にセット
' ※マイナス値にすることで、画面奥から手前へ走ってくるようになる
Dim VelocityZ=-15 As Single

Function MoveCar(dw As DWord) As DWord
    Dim i As Long

    '再生時間を20秒にする
    Dim playtime=20*10 As Long

    For i=0 To playtime
        'pAudioが破棄されたとき(アプリケーションがユーザーによって終了されたとき)
        If pAudio=0 Then Exit Function

        '救急車の新しい位置を計算
        CarZ=CarZ+VelocityZ/10
        pAudio->SetPosition(0,0,CarZ)

        'リスナー/音源の設定を更新
        pListener->CommitSettings()

        '0.1秒間隔でループさせる
        Sleep(100)
    Next

    'アプリケーションを終了
    PostMessage(hMainWnd,WM_QUIT,0,0)
End Function

●InitProc関数のコーディング

CAudio3D及びCListenerオブジェクトの生成を行います。別途、サイレン音が必要になりますが、お持ちでない方はsiren.wavをダウンロードしておきましょう。

まずはpListenerオブジェクトを生成してリスナーの設定を行います。今回のプログラムでは、リスナーは原点座標[0,0,0]でZ軸の正の方向を向いて静止している状態にしておきましょう。

次に、サイレン音を管理するpAudioオブジェクトを生成します。

Function InitProc()
    'DirectXを初期化
    If dx_Init(hMainWnd,ScreenX,ScreenY,FALSE)=0 Then
        InitProc=0
        Exit Function
    End If

    'マウスカーソルを非表示にする
    ShowCursor(FALSE)

    ' TODO: この位置にアプリケーションの初期化コードを記述してください。

    'リスナーの設定
    pListener=New CListener
    pListener->SetPosition(0,0,0)          '位置
    pListener->SetVelocity(0,0,0)          '速度
    pListener->SetOrientation(0,0,1,0,1,0) '方向

    '音源を生成し、WAVEファイルを読み込む
    pAudio=New CAudio3D
    pAudio->Load("siren.wav")

    '音源の設定
    pAudio->SetMinDistance(5)            '最短距離(単位はメートル)
    pAudio->SetMaxDistance(300)          '最長距離(単位はメートル)
    pAudio->SetPosition(0,0,CarZ)        '位置(単位はメートル)
    pAudio->SetVelocity(0,0,VelocityZ)   '速度(単位はメートル毎秒)

    'リスナー/音源の設定を更新
    pListener->CommitSettings()

    '再生
    pAudio->Play()

    '救急車を走行させるためのスレッドを生成
    Dim dw As DWord
    CreateThread(ByVal 0,0,AddressOf(MoveCar),0,0,VarPtr(dw))

    InitProc=1
End Function

●QuitProc関数のコーディング

pAudio及びpListenerオブジェクトを解放します。

Sub QuitProc()
    ' TODO: この位置にアプリケーションの終了処理を記述してください。

    '停止
    pAudio->Stop()

    'オブジェクトを破棄
    Delete pAudio
    pAudio=0
    Delete pListener

    'DirectXの終了処理
    dx_Quit()
End Sub

Load関数で "siren.wav" を読み込む際に、カレントディレクトリの設定がうまくいっていないと失敗するようです。実行してもエラーがでてしまう場合は、"siren.wav" を絶対パスで指定してみてください。

どうですか?救急車が走り去るようなドップラー効果、お楽しみいただけたでしょうか。この他、エンジン音、列車の汽笛などWAVEファイルを交換して様々な3Dサウンドを試してみると面白いかもしれません♪



講座インデックスへ戻る ©2005 Discoversoft