忍者ブログ

Memeplexes

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


OpenAL 一定の周波数のBufferオブジェクトを簡単(?)に作る [C#]

alutCreateBufferWaveform
以前"ラ"の音を表す音波のデータをbyte[]でいちいち手作業で作りました。
自分で音の波の形を完全にコントロールしたい場合はそれで良いのでしょうが、単に音を出したいだけの時もあるでしょう。

そういうときに便利なのが、alutCreateBufferWaveform関数です。

ALuint alutCreateBufferWaveform (
        ALenum waveShape,
        ALfloat frequency,
        ALfloat phase,
        ALfloat duration
        ) ;


この関数は、一定の周波数の音を作ることが出来ます。(波形や移送、再生時間も制御できます)

waveShapeは波のです。セットできる値には次の5つがあります:

名前
ALUT_WAVEFORM_SINE 0x100
ALUT_WAVEFORM_SQUARE 0x101
ALUT_WAVEFORM_SAWTOOTH 0x102
ALUT_WAVEFORM_WHITENOISE 0x103
ALUT_WAVEFORM_IMPULSE 0x104

(※SineとSquare, SawToothについてはWikipediaの波形の項目に図が載っています。が、残りのWhitenoise、Impulseの図はありません。グーグルのイメージ検索でそれらしき図は出てくるのですが・・・・・・。)

frequencyは波の周波数です。これが大きければ大きいほど高い音が出て、小さければ小さいほど低い音が出ます。例えば、現在"ラ"の音の周波数は440ですが、これを2倍の880にすると高い"ラ"の音になります。(220なら低い"ラ"です)

phaseは波の位相です。波には周期があるのですが、この周期のどの地点から波を始めるかを表します。(といっても、1周期はラの音で1/440秒ですから、周期の中のどの地点から始まってもそんなに変わらないように思えます。とりあえず0にしておけばいいでしょう)ちなみに、この周期は1周期を360°として角度で表します。

durationは波の時間です。1秒なら1です。
using System;
using System.Runtime.InteropServices;

class AudioSource
{
    [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);

    private int name;

    public AudioSource()
    {
        int[] names = new int[1];
        alGenSources(names.Length, names);
        this.name = names[0];
    }

    ~AudioSource()
    {
        alDeleteSources(1, new int[] { this.name });
    }

    public int Buffer
    {
        set
        {
            alSourcei(this.name, AL_BUFFER, value);
        }
    }

    public void Play()
    {
        alSourcePlay(this.name);
    }
}

class AudioBuffer
{
    [DllImport("alut.dll")]
    static extern int alutCreateBufferWaveform(
        WaveForm waveShape,
        float frequency,
        float phase,
        float duration
        );

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

    private int name;

    public int Name { get { return this.name; } }

    public AudioBuffer(WaveForm waveShape, float frequency, float phase, float duration)
    {
        this.name = alutCreateBufferWaveform(waveShape, frequency, phase, duration);
    }

    ~AudioBuffer()
    {
        alDeleteBuffers(1, new int[] { name });
    }

}

enum WaveForm
{
    //ALUT_WAVEFORM_SINE
    Sine = 0x100,
    //ALUT_WAVEFORM_SQUARE
    Square,
    //ALUT_WAVEFORM_SAWTOOTH
    SawTooth,
    //ALUT_WAVEFORM_WHITENOISE
    WhiteNoize,
    //ALUT_WAVEFORM_IMPULSE
    Impulse
}

class Program
{
    [DllImport("alut.dll")]
    static extern void alutInit(IntPtr argcp, string[] argv);
    [DllImport("alut.dll")]
    static extern void alutExit();


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

        foreach (WaveForm waveShape in Enum.GetValues(typeof(WaveForm)))
        {
            System.Console.WriteLine(waveShape);
            AudioBuffer buffer = new AudioBuffer(waveShape, 440, 0, 1);
            AudioSource source = new AudioSource();
            source.Buffer = buffer.Name;
            source.Play();
            System.Threading.Thread.Sleep(2000);
        }

        alutExit();
    }
}


このサンプルは、5つの全ての波形をつかって、"ラ"の音を出していきます。
2番目のSquareの音がうるさいので注意してくださいね。
あと、どうやら4番目のWhiteNoizeは音がしないようです。

拍手[0回]


OpenAL ファイルイメージからBufferを作成 [C#]

alutCreateBufferFromFileImage
ファイル名からBufferオブジェクトを作るのはalutCreateBufferFromFile関数でしたが、もうちょっと柔軟にできないものでしょうか?

たとえばインターネット上からwavファイルをダウンロードして、それを再生するような場合です。
いちいちハードディスクに保存しなくても再生できないものでしょうか?

alutCreateBufferFromFileImage関数がそれを可能にします。
この関数は、wavファイルのbyte[] からBufferオブジェクトを作成します。
つまり、wavファイルがハードディスク上に保存されている必要はありません。中身のbyte配列がメモリにあればいいのです。

ALuint alutCreateBufferFromFileImage(const ALvoid *data, ALsizei length);

成功すれば生成されたBufferオブジェクトの名前を、失敗すればAL_NONE( = 0)を返します。
using System;
using System.Runtime.InteropServices;

class AudioSource
{
    [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);

    private int name;

    public AudioSource()
    {
        int[] names = new int[1];
        alGenSources(names.Length, names);
        this.name = names[0];
    }

    ~AudioSource()
    {
        alDeleteSources(1, new int[] { this.name });
    }

    public int Buffer
    {
        set
        {
            alSourcei(this.name, AL_BUFFER, value);
        }
    }

    public void Play()
    {
        alSourcePlay(this.name);
    }
}

class AudioBuffer
{
    [DllImport("alut.dll")]
    static extern int alutCreateBufferFromFileImage(byte[] data, int dataLength);

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

    private int name;

    public int Name { get { return this.name; } }

    public AudioBuffer(byte[] fileImage)
    {
        this.name = alutCreateBufferFromFileImage(fileImage, fileImage.Length);
    }

    ~AudioBuffer()
    {
        alDeleteBuffers(1, new int[] { name });
    }

}

class Program
{
    [DllImport("alut.dll")]
    static extern void alutInit(IntPtr argcp, string[] argv);
    [DllImport("alut.dll")]
    static extern void alutExit();


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

        AudioBuffer buffer = new AudioBuffer(
            System.IO.File.ReadAllBytes("damage1.wav")
            );
        AudioSource source = new AudioSource();
        source.Buffer = buffer.Name;
        source.Play();
        System.Threading.Thread.Sleep(2000);

        alutExit();
    }
}


ここでは、File.ReadAllBytesメソッドを使っていったん"damage1.wav"をメモリ上にbyte[]として読み込んでいます。
それをalutCreateBufferFromFileImageに渡しているのです。

実行結果はあいかわらず「ボガァン」という音です。

拍手[0回]


OpenAL WAVEファイルの再生 [C#]

OpenAL.netのおかげでモチベーションが下がりっぱなしなのですが気を取り直していこうと思います。

alutCreateBufferFromFile
OpenALでは音波のデータを直接再生することが出来ますが、場合によってはこれは低レベルすぎると思う場合があるかもしれません。

たとえば、単に音のファイルを再生したい場合です。

「宇宙船に弾が当たったらdamage1.wavというファイルを再生したい」というような時には、この方法はめんどうです。

しかしありがたいことに、alutはファイルからBufferを作る関数を用意してくれています。
alutCreateBufferFromFileというのがそれで、ファイル名からBufferを作ってその名前を返します。

int alutCreateBufferFromFile (const  char *fileName) ;

失敗した時にはAL_NONE( = 0)を返します。




using System;
using System.Runtime.InteropServices;

class AudioSource
{
    [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);

    private int name;

    public AudioSource()
    {
        int[] names = new int[1];
        alGenSources(names.Length, names);
        this.name = names[0];
    }

    ~AudioSource()
    {
        alDeleteSources(1, new int[] { this.name });
    }

    public int Buffer
    {
        set
        {
            alSourcei(this.name, AL_BUFFER, value);
        }
    }

    public void Play()
    {
        alSourcePlay(this.name);
    }
}

class AudioBuffer
{
    [DllImport("alut.dll")]
    static extern int alutCreateBufferFromFile(string fileName);

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

    private int name;

    public int Name { get { return this.name; } }

    public AudioBuffer(string fileName)
    {
        this.name = alutCreateBufferFromFile(fileName);
    }

    ~AudioBuffer()
    {
        alDeleteBuffers(1, new int[] { name });
    }

}

class Program
{
    [DllImport("alut.dll")]
    static extern void alutInit(IntPtr argcp, string[] argv);
    [DllImport("alut.dll")]
    static extern void alutExit();


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

        AudioBuffer buffer = new AudioBuffer("damage1.wav");
        AudioSource source = new AudioSource();
        source.Buffer = buffer.Name;
        source.Play();
        System.Threading.Thread.Sleep(2000);

        alutExit();
    }
}


このサンプルでは、damage1.wavという、XNAのSpaceWarゲームから拝借したファイル(Content/Audio/Waves/Weapons/damage1.wav)を再生しています。(「ボガァン」という感じの音です。)

拍手[0回]


OpenAL.net

ここ最近、OpenALのマネージト・ラッパーをC#で書いてOpenAL.netとでも名づけようと思っていたのですが、じつはそのものズバリがすでにあるようです。(マヌケすぎます……)

OpenAL.NET

まだソースコードはちらっと見ただけですが、なかなか良い品質のようです。
これでは僕がやることはなにもありませんね……。

拍手[0回]


        
  • 1
  • 2