忍者ブログ

Memeplexes

プログラミング、3DCGとその他いろいろについて

OpenAL 音源とリスナーの位置の変更 [C#]

OpenALではSourceオブジェクト(音源)の3次元空間中の位置を変更して、音の大きさを変えることが出来ます。
リスナー(聞き手)に近づけば音は大きくなりますし、遠ざかれば小さくなります。
遠くの音は小さく、近くの音は大きく聞こえるものです。

デフォルトでは、SourceオブジェクトもListener(インスタンス(?)は一つだけでシングルトンの扱いです。SourceやBufferのような名前(Name)は持っていません。)も位置は{0, 0, 0}だそうです。
これを、OpenALの関数を使って変えることで音の強さによる遠近感が出せるようです。

alSource3f
Sourceオブジェクトの位置を変えるのにはalSource3f関数が使えます。(「使えます」というのは、別の関数、たとえばalSourcefv, alSource3i, alSourceivを使って位置をセットすることも出来るからです。しかし、alSource3fがもっとも使いやすさと柔軟性の面でバランスが取れています。ポインタを使わなくていいですし、位置を表すのにintではなくfloatを使うことが出来るからです。)

void alSource3f(
        int sourceName,
        int propertyType,
        float x, float y, float z
        );


引数はお決まりです。
sourceNameは値をセットするSourceオブジェクトの名前。
propertyTypeはセットする属性を表す定数(ここではAL_POSITION = 0x1004)。
x, y, zはそれぞれ位置をあらわします。

この関数を使うと、位置だけではなく速度(AL_VELOCITY = 0x1006)もセットできます。速度からはドップラー効果を再現できます。

using System;
using System.Runtime.InteropServices;
using System.Threading;

class Program
{
    //OpenAL Utility Toolkit (Alut)の関数をインポート
    [DllImport("alut.dll")]
    static extern bool alutInit(IntPtr argcp, string[] argv);

    [DllImport("alut.dll")]
    static extern bool alutExit();

    [DllImport("alut.dll")]
    static extern int alutCreateBufferHelloWorld();



    //OpenALの関数をインポート
    [DllImport("OpenAL32.dll")]
    static extern void alGenSources(int resultSize, int[] result);

    [DllImport("OpenAL32.dll")]
    static extern void alDeleteSources(int nameCount, int[] sourceNames);

    [DllImport("OpenAL32.dll")]
    static extern void alSourcei(int sourceName, int propertyType, int value);
    const int AL_BUFFER = 0x1009;

    [DllImport("OpenAL32.dll")]
    static extern void alSourcePlay(int sourceName);

    [DllImport("OpenAL32.dll")]
    static extern void alSource3f(
        int sourceName, int propertyType,
        float v1, float v2, float v3
        );
    const int AL_POSITION = 0x1004;


    static void Main()
    {
        alutInit(IntPtr.Zero, null);

        int[] sources = new int[1];
        alGenSources(sources.Length, sources);
        alSourcei(sources[0], AL_BUFFER, alutCreateBufferHelloWorld());

        for (int i = 0; i < 4; i++)
        {
            alSource3f(sources[0], AL_POSITION, 0, 0, -i);
            alSourcePlay(sources[0]);
            Thread.Sleep(1500);
        }

        alDeleteSources(sources.Length, sources);

        alutExit();
    }
}


このサンプルでは、音源をどんどん聞き手から離していっています。
ですから、"Hello, World!" "Hello, World!" "Hello, World!", "Hello, World!"と小さくなるわけです。


alListener3f
ここまでは音源を表すSourceオブジェクトの位置を変えていましたが、リスナー(聞き手)の位置を変えることも出来ます。
聞き手が音から離れていっても音は小さくなるでしょうからね。

リスナーの位置を変えるには、alListener3f関数が使えます。(やはりalListener3ialListeneriv, alListenerfvみたいな別の関数も使えますが、位置のセットにはこれが一番適しています)

void alListener3f(int propertyType, float x, float y, float z);

この関数はalSource3fにとてもよく似ていますが、ただひとつ、第一引数にオブジェクトを表す名前がありません。
Listenerはシングルトンなので名前は必要ないのです。

その他の引数は全く同じです。
propertyTypeは設定する属性を表す定数(位置をセットしたいのならSourceのときと同じようにAL_POSITION)、
x, y, zは位置の成分です。


using System;
using System.Runtime.InteropServices;
using System.Threading;

class Program
{
    //OpenAL Utility Toolkit (Alut)の関数をインポート
    [DllImport("alut.dll")]
    static extern bool alutInit(IntPtr argcp, string[] argv);

    [DllImport("alut.dll")]
    static extern bool alutExit();

    [DllImport("alut.dll")]
    static extern int alutCreateBufferHelloWorld();



    //OpenALの関数をインポート
    [DllImport("OpenAL32.dll")]
    static extern void alGenSources(int resultSize, int[] result);

    [DllImport("OpenAL32.dll")]
    static extern void alDeleteSources(int nameCount, int[] sourceNames);

    [DllImport("OpenAL32.dll")]
    static extern void alSourcei(int sourceName, int propertyType, int value);
    const int AL_BUFFER = 0x1009;

    [DllImport("OpenAL32.dll")]
    static extern void alSourcePlay(int sourceName);

    const int AL_POSITION = 0x1004;

    [DllImport("OpenAL32.dll")]
    static extern void alListener3f(int propertyType, float x, float y, float z);


    static void Main()
    {
        alutInit(IntPtr.Zero, null);

        int[] sources = new int[1];
        alGenSources(sources.Length, sources);
        alSourcei(sources[0], AL_BUFFER, alutCreateBufferHelloWorld());

        for (int i = 0; i < 4; i++)
        {
            alListener3f(AL_POSITION, 0, 0, i);
            alSourcePlay(sources[0]);
            Thread.Sleep(1500);
        }

        alDeleteSources(sources.Length, sources);

        alutExit();
    }
}


実行結果は先ほどと同じになるはずです。
ただ違うのは、このサンプルでは音源ではなく聞き手のほうを動かしているということです。















拍手[1回]

PR