WisdomSoft - for your serial experiences.

サウンド再生

任意の Wave 形式ファイル(拡張子 .wav)をコンテンツプロジェクトに登録し、ゲーム内で再生する方法を紹介します。

Waveファイルから再生する

ゲーム開発では多くの資源がグラフィックスに費やされますが、ゲームを構成する重要な要素はグラフィックスだけではありません。意識されることは少ないですが、音による演出はユーザー体験を劇的に変化させます。技術的にも、デザイン的にも、またはビジネス的にも、グラフィックスに比べてサウンドは不遇な扱いを受けることが多いですが、その役割の重要性はグラフィックスに劣るものではありません。

XNA Framework で音声を再生・制御する方法は、大きく 3 通りの方法に分かれます。

  • サウンドエフェクト - 標準的な同人ゲーム向け
  • メディアプレイヤー - BGM再生
  • XACT - プロフェッショナル向け

1 つは、本稿で説明するサウンドエフェクトを用いた方法です。登録した音声ファイルを、そのままゲーム内で再生できる単純な方式で、多くのゲームに適しています。メディアプレイヤーを利用した BGM の再生は、BGM の再生やゲーム音楽の鑑賞モードに適しているでしょう。

XACT は特殊で Xbox360 のコンソールゲーム開発にも使われているプロフェッショナル向けの環境です。Windows PC 及び Xbox 360 向けのゲームでしか使えませんが、サウンドデザイナーによるサウンドデザインと開発者が分業できる体制が必要な場合に威力を発揮します。

この場では、サウンドエフェクトを用いて音声ファイルを再生する、最も簡単な手法から紹介します。まず最初に、再生する Wave 形式のファイルを用意してください。通常、拡張子は .wav で保存されているファイルです。この形式のファイルは MP3 などと異なり未圧縮の状態なので、再生時間が長い場合は容量が膨大になるので注意が必要です。テストには数秒の効果音が望ましいでしょう。

基本的な扱いはテクスチャやフォントと同じです。用意した Wave ファイルをコンテンツプロジェクトに登録し、アセットに変換したうえでゲームから読み込みます。図1のようにコンテンツプロジェクトに Wave ファイルを追加し、任意のアセット名を設定してください。この場では「TestSound」という名前とします。また「コンテンツ プロセッサ」が「サウンド エフェクト : XNA Framework」になっていることを確認してください。

図1 音声ファイルの追加
図1 音声ファイルの追加

登録した音声ファイルは ContentManager クラスの Load() メソッドを通して Microsoft.Xna.Framework.Audio.SoundEffect クラスのオブジェクトとして受け取ります。

Microsoft.Xna.Framework.Audio.SoundEffect クラス
public sealed class SoundEffect : IDisposable

この SoundEffect クラスのインスタンスが、内部に音声データを保持する 1 つのサウンドを表します。読み込んだサウンドを再生するには Play() メソッドを呼び出します。

SoundEffect クラス Play() メソッド
public bool Play ()

このメソッドは SoundEffect インスタンスが保存する波形データから新しいサウンドを再生します。サウンドは終了まで再生され、その管理は SoundEffect クラス内部で行われます。よって開発者は Play() メソッドを呼び出した後に、サウンドを管理する必要はありません。効果音の再生に適しているでしょう。

Play() メソッドは、正常にサウンドを再生できれば true を返します。それ以外の場合、例えばサウンドが重ねて再生されすぎているような場合は false が返されます。

コード1
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Input;

public class TestGame : Game
{
    public static void Main(string[] args)
    {
        using (Game game = new TestGame()) game.Run();
    }

    private GraphicsDeviceManager graphicsDeviceManager;
    private SoundEffect soundEffect;
    private KeyboardState prevKeyState;

    public TestGame()
    {
        graphicsDeviceManager = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
    }

    protected override void LoadContent()
    {
        soundEffect = Content.Load<SoundEffect>("TestSound");
        base.LoadContent();
    }
    
    protected override void Update(GameTime gameTime)
    {
        KeyboardState keyState = Keyboard.GetState();
        if (keyState.IsKeyDown(Keys.Enter) && prevKeyState.IsKeyUp(Keys.Enter))
            soundEffect.Play();
        prevKeyState = keyState;

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.White);
        base.Draw(gameTime);
    }
}

コード1はコンテンツプロジェクトに登録した TestSound アセットを SoundEffect オブジェクトとして読み込んでいます。Update() メソッドでキーボードの Enter キーが押されたかどうかを判定し、押された瞬間にサウンドを再生するという単純なプログラムです。連続して Enter キーを入力した場合は、前のサウンドが再生中でも、新しいサウンドが重ねて再生されます。

ストリームからの読み込み

タイトルストレージや Web、またはユーザーのドキュメントなど、アセット以外から音声を読み込むには FromStream() メソッドを使います。

SoundEffect クラス FromStream() メソッド
public static SoundEffect FromStream (
         Stream stream
)

stream パラメータには、音声データとして読み取る Wave ファイルの先頭を指すストリームを指定します。加えて、対象の音声データはモノラルまたはステレオのいずれかで、サンプルは 8 ビットまたは 16 ビット、かつサンプリングレートが 8000Hz ~ 48000Hz の範囲でなければなりません。

コード2
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Input;
using System.IO;

public class TestGame : Game
{
    public static void Main(string[] args)
    {
        using (Game game = new TestGame()) game.Run();
    }

    private GraphicsDeviceManager graphicsDeviceManager;
    private SoundEffect soundEffect;
    private KeyboardState prevKeyState;

    public TestGame()
    {
        graphicsDeviceManager = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
    }

    protected override void LoadContent()
    {
        using (Stream stream = TitleContainer.OpenStream("TestSound.wav"))
        {
            soundEffect = SoundEffect.FromStream(stream);
        }
        base.LoadContent();
    }
    
    protected override void Update(GameTime gameTime)
    {
        KeyboardState keyState = Keyboard.GetState();
        if (keyState.IsKeyDown(Keys.Enter) && prevKeyState.IsKeyUp(Keys.Enter))
            soundEffect.Play();
        prevKeyState = keyState;

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.White);
        base.Draw(gameTime);
    }
}

コード2はタイトルストレージに配置されている TestSound.wav というファイルを読み込みます。それ以外はコード1と同じです。