tanaka's Programming Memo

プログラミングについてのメモ。

音を鳴らす

データ形式

以下の形式のデータを自作したり、フリー素材から探して用意する。

  • 効果音
    • WAVE(wav)形式で準備する。
  • BGM
    • MIDI(SMF)、MP3、oggのいずれかで準備する。
    • WAVEも使えるが、サイズが大きくなるのでMP3やoggに変換した方がよい。

実装

DirectSoundを使って実装する。DirectXSDKがインストールされていること。

環境設定
  • サウンド再生機能を組み込みたいプロジェクトを開く。

参照設定に「Microsoft.DirectX」と「Microsoft.DirectX.Sound」を追加する。

  • 【ソリューションエクスプローラー】の【参照設定】を右クリックして【参照の追加】を選択。

  • [Ctrl]キーを押しながら、「Microsoft.DirectX」と「Microsoft.DirectX.DirectSound」を選択して【OK】を押す。

  • もう一度【参照設定】を右クリックして【参照の追加】を選択。
  • 【COM】タブを選択。
  • Windows Media Player】を選択する。複数ある場合は、パスの最後が「wmp.dll」で終わっているものを選んで【OK】を押す。


DirectSoundを操作するためのクラスを生成する。

  • 【ソリューションエクスプローラ】からプロジェクト名を右クリックして、【追加】→【クラス】を選択。
  • ファイル名を「CDirectSound」として追加する。
  • 作成された「CDirectSound.cs」を以下のソースコードにする。
using System;
using Microsoft.DirectX;
using Microsoft.DirectX.DirectSound;
using System.Windows.Forms;

/**
 * DirectSound使用クラス
 * @auther YuTanaka
 */

public class CDirectSound
{
    public Device devSound = null;
    public WMPLib.WindowsMediaPlayer mediaPlayer = new WMPLib.WindowsMediaPlayer();
    public SecondaryBuffer[] bufSec = null;
    public static string sErr = "";

	public CDirectSound(Form owner)
	{
        try
        {
            // デバイス作成
            devSound = new Device();
            // 協調レベルの設定
            devSound.SetCooperativeLevel(owner, CooperativeLevel.Priority);
        }
        catch(Exception e) 
        {
            e.ToString();
        }
	}

    // 解放処理
    ~CDirectSound()
    {
        releaseBufSec();
        if (devSound != null)
        {
            devSound.Dispose();
            devSound = null;
        }
    }

    // セカンダリバッファを解放する
    public void releaseBufSec()
    {
        int i;
        if (bufSec != null)
        {
            for (i = 0; i < bufSec.Length; i++)
            {
                if (bufSec[i] != null)
                {
                    bufSec[i].Dispose();
                    bufSec[i] = null;
                }
            }
            bufSec = null;
        }
    }

    /** 読み込むファイルの上限数を設定する。*/
    public void init(int max)
    {
        int i;
        releaseBufSec();
        
        // 新しく領域を定義
        bufSec = new SecondaryBuffer[max];
        for (i = 0; i < max; i++)
        {
            bufSec[i] = null;
        }
    }

    /** 指定の音声データを読み込む*/
    public bool loadWave(int idx, string fname)
    {
        try
        {
            bufSec[idx] = new SecondaryBuffer(fname,devSound);
        }
        catch (Exception e)
        {
            sErr = "[loadWaveエラー]"+e.ToString();
            return false;
        }
        return true;
    }

    /** 指定の音声を再生する*/
    public void play(int idx,bool loop)
    {
        if ((bufSec != null) && (bufSec[idx] != null))
        {
            bufSec[idx].SetCurrentPosition(0);
            if (!loop)
            {
                bufSec[idx].Play(0, BufferPlayFlags.Default);
            }
            else
            {
                bufSec[idx].Play(0, BufferPlayFlags.Looping);
            }
        }
    }

    /** 指定のサウンドを停止する*/
    public void stop(int idx)
    {
        if ((bufSec != null) && (bufSec[idx] != null)) {
            bufSec[idx].Stop();
        }
    }

    /** MIDI/MP3を再生*/
    public void playBGM(string fname)
    {
        mediaPlayer.URL = fname;
        mediaPlayer.settings.setMode("loop", true);
        mediaPlayer.controls.play();
        
    }

    /** MIDI/MP3を停止*/
    public void stopBGM()
    {
        mediaPlayer.controls.stop();
    }
}

プロジェクトに組み込む

参照設定とCDirectSound.csがプロジェクトに組み込めたら、プログラムの初期化、データの読み込み、再生を実装する。

変数の追加
  • 音楽再生を実装したいクラスに以下の変数宣言を追加する。
        CDirectSound dsound;
データを用意する

音声データは、プロジェクトフォルダ内のbin\Debugフォルダ内に入れておく。

ここからの例では以下のような音声を再生することを前提としている。

  • 効果音0:cursor1.wav
  • 効果音1:decide1.wav
  • 効果音2:tama1.wav
  • BGM0:Galaxy.ogg
  • BGM1:tam-n01.mid
  • BGM2:tamsp02.mp3

サンプルプロジェクトでは、「TAM Music Factory」様のページから上記データをいただいた。

初期化と読み込み

サウンド環境の初期化と、音楽データの読み込みは、フォームが表示された直後に行うとよい。

音楽データの読み込みは、効果音とBGMでタイミングが違う。

効果音は、初期化のタイミングで必要なデータを全て読み込むようにする。効果音は鳴らしたいタイミングですぐに鳴らしたいのでこのようにする。今回は3種類の効果音を読み込むようにする。

BGMは、データサイズが大きいため、予め読み込むことはせず、再生したい時に読み込んで再生する。3種類のBGMが用意されているが、ここでは何もしない。

  • Formを選び、【プロパティ】ウィンドウの【Shown】イベントをダブルクリックする。

  • 開いた「form1_Shown()」関数内に以下のような初期化プログラムを記載する。実際に読み込むファイル数やWAVファイル名は、プロジェクトに合わせて変更のこと。
            // DirectSoundの初期化
            dsound = new CDirectSound(this);
            // 利用する効果音数を指定する。
            // 今回は3種類なので3を設定。
            dsound.init(3);
            // 効果音の読み込み。
            dsound.loadWave(0, "cursor1.wav");
            dsound.loadWave(1, "decide1.wav");
            dsound.loadWave(2, "tama1.wav");
再生

初期化と読み込みが完了したら、あとは音を再生したいタイミングで再生関数を呼び出す。

効果音の再生

効果音を再生したい場合はplay(<効果音番号>,<ループフラグ>)関数を呼ぶ。

  • 効果音番号とは、読み込みの時に指定した番号。上記の例だと「cursor1」を再生したい時は0。「decide1」を再生したい時は1。「tama1」を再生したい時は2を指定することになる。
  • ループフラグはtrueかfalseで指定する。trueを指定すると、stop(<効果音番号>)を呼び出すまでずっと再生し続ける。
            // cursor1を1回だけ再生したい時
            dsound.play(0, false);
効果音の停止

効果音を途中で停止させたい時は、stop(<効果音番号>)関数を呼ぶ。

            // cursor1を停止したい時
            dsound.stop(0);
BGMの再生

BGMを再生したい時は、playBGM("ファイル名")関数を呼ぶ。

BGMは曲の最後まで達すると自動的にループ再生するようになっている。BGMを停止したい場合は、次の曲を鳴らし始めるか、stopBGM()関数を呼ぶ。

            // Galaxy.oggを再生したい時
            dsound.playBGM("Galaxy.ogg");

oggファイルを再生したい場合、以下のような確認ダイアログが表示される場合がある。

チェックを入れて、【はい】を選択するとそのまま再生できると思う。

*OGGが再生できない時
上記で【はい】を選んでも音が鳴らない時は、以下から「OGG」をDirectSoundで鳴らすためのプラグインをインストールする。
http://www.free-codecs.com/Ogg_DirectShow_Filters_download.htm

  1. Download [ Ogg DirectShow Filters 0.9.9.5 - Stable ]を選択
  2. 【実行】を選択
  3. 【はい】を選択
  4. 【I Agree】を選択

以上ができたら、再度再生を試してみてほしい。

BGMの停止

再生中のBGMを停止したい時は、stopBGM()関数を呼ぶ。

            // BGMを停止する。
            dsound.stopBGM();

サンプルプロジェクト

CDirectSoundを利用して音を鳴らすサンプルのプロジェクト(sampleDirectSound.zip)

Form1.csを読んで、利用方法の参考にして欲しい。

CDirectSound.csは変更する必要はない。

64bitのPCだと、Managed DirectXがそのままでは動かない。以下の設定を行うこと。

  1. メニューの【プロジェクト】→一番下の「プロジェクトのプロパティ」を選択。
  2. 左から【ビルド】タブを選択。
  3. 【プラットフォームターゲット】を【x86】に変更。

以上でリビルドして実行する。