Top > ComputerGraphics > SharpDX > SoundEffectWithToolkit
Last-modified: Thu, 17 Jul 2014 10:34:12 JST
Counter:2092 Today:1 Yesterday:0 Online:9
このエントリーをはてなブックマークに追加

SharpDX.Toolkit を使って音声を読み込んで再生する

About

SharpDX には XNA ライクに、簡単に、DirectX を利用したアプリケーションを実装するための Toolkit が用意されています。この Toolkit を利用すると、テクスチャなどのリソースを簡単に読み込むことができます。

音声ファイルの読み込みについては、2.6 系から実装されたようですが、2014.07.17 現在の実装では、音声ファイルの読み込み、およびその利用方法が商用ややこしいのでここでまとめておきます。Web の記事では XAudio を利用して自ら実装する方法の方が多く見つかります。XNA と同じような手順を踏めないので、XNA から引っ越ししてきた人も戸惑うかもしれません。

バージョンアップによってここで開設する問題の一部またはすべてが解決する可能性があります。 ソースコードを読むのが億劫なので、ここで紹介する手法の正確な動作情報については確認していません。必要なら SharpDX のソースコードを読むようにしてください。

How to

まずは音声ファイル(オーディオファイル)を読み込めるようにしておきます。標準では Content ファイルの下に対象のファイルを配置し、ビルドアクションを ToolkitAudio に設定します。ここでは仮に、読み込むファイルを Sample.wav だとします。

音声ファイルは特に限定されない限りは wav 形式が良さそうです。mp3 形式の場合、その mp3 フォーマットの内容にも寄るのかもしれませんが、InvalidOperationException - Invalid RIFF format が発生する可能性があります。その他のフォーマットについては検証していません。

AudioManager と SoundEffect, SoundEffectInstance を使うのが最も実用的で簡単な方法だと思います。これらを使うために、プロジェクトに、SharpDX.Toolkit.Audio.dll への参照を追加しておきます。NuGet パッケージから生成した標準のプロジェクトには参照が追加されていないので注意してください。

音声データも、他のテクスチャなどのリソースと同じように、Content.Load によって読み込むことができます。

AudioManager audioManager;
SoundEffect se_sample;
SoundEffectInstance sei_sample;
…
protected override void LoadContent()
{
…
    this.audioManager = new AudioManager(this);
    this.se_sample = Content.Load<SoundEffect>("Sample");
…
}

ここで重要なのが、AudioManager のインスタンスを生成することです。 このインスタンスが生成されていない場合、InvalidOperationException - Cannot read WaveBank without AudioManager. が発生します。一方でインスタンスを生成しておくと、この例外は発生しません。分かり易さのためには次のように書いても良いかもしれません。

protected override void LoadContent()
{
…
    this.audioManager = new AudioManager(this);
    this.se_sample = audioManager.Game.Content.Load<SoundEffect>("Sample");
…
}

SoundEffect を作った段階で、読み込んだ音声を再生することはできます。ただし SoundEffect には Stop や Pose などのメソッドは実装されておらず、それらは SoundEffectInstance に実装されています。まずは、SoundEffect で再生してみます。ここで、LoadContent の中で、読み込んだ直後に再生しようとすると、NullReferenceException が発生する点に注意してください。

protected override void LoadContent()
{
…
    this.audioManager = new AudioManager(this);
    this.se_sample = Content.Load<SoundEffect>("Sample");
    this.se_sample.Play();//NullReferenceException
…
}

再生が可能になるタイミングは、LoadContent の処理が完了した以降になっています。したがって、最初の Update が呼び出されるより前の段階の、BeginRun メソッドの時点から再生が可能になります。NuGet パッケージなどから自動生成されたコードには BeginRun が実装されていないので追記します。

protected override void BeginRun()
{
…
    this.se_sample.Play();
…
}

LoadContent した直後に再生できない問題と同様の問題が、SoundEffectInstance のインスタンス生成時に発生します。つまり、SoundEffect を読み込んだ直後に、その SoundEffect を利用して SoundEffectInstance のインスタンスを生成すると、NullReferenceException が発生します。

AudioManager audioManager;
SoundEffect se_sample;
SoundEffectInstance sei_sample;
…
protected override void LoadContent()
{
…
    this.audioManager = new AudioManager(this);
    this.se_sample = Content.Load<SoundEffect>("Sample");
    this.sei_sample.Create();//NullReferenceException
…
}

SoundEffectInstance のインスタンスを生成するには、SoundEffect.Create メソッドを利用します。NullReferenceException の問題を解決策するには、BeginRun メソッド内で SoundEffect.Create メソッドを実行します。

AudioManager audioManager;
SoundEffect se_sample;
SoundEffectInstance sei_sample;
…
protected override void LoadContent()
{
…
    this.audioManager = new AudioManager(this);
    this.se_sample = Content.Load<SoundEffect>("Sample");
…
}
…
protected override void BeginRun()
{
    this.sei_sample = this.se_sample.Create();
    this.sei_sample.Play();
}

その他の情報

  • 音量は 0.0 の時に無音で標準を 1.0 とする値のようです。

オーディオファイルの再生速度が変更される問題

複数のオーディオ(wav)ファイルを読み込むと、後から読み込んだオーディオファイルのピッチが何かの原因で変更されてしまうことがあるようです。

不具合が起きるファイルに問題がある可能性があります。もちろんプログラム側が解決するのが良いのですが、SharpDX のソースコードを書き換えて再コンパイルする必要が生じるので、対象のファイルを何かしらのソフトで再エンコードしてみるのが良いと思います。