5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

リソースの音声データを再生する

Last updated at Posted at 2019-10-31

音声データを再生したいが、waveファイルやmp3ファイルを別ファイルで配布しないでリソースで同梱して扱いたい。というのを叶える方法を調べてみた。

  • 扱う音声データはwavとmp3(NAudioが扱えるものなら何でも良いはず)
  • wavはPlaySoundを使用し、mp3はNAudioを使用した

Visual Studio 2019を使っているが、昔のバージョンでもいけるはず。またusing変数宣言はC# 8.0の記法なので適宜置き換えて読んでほしい。
また、エラー処理や例外処理は端折っているので、適宜補うべし。

ソリューション構成

C#のプロジェクトを作成し、あらかじめ音声データファイルをリソースに登録しておく。
wavの場合、リソースの種別は「オーディオ」となる。
mp3の場合、リソースの種別は「ファイル」となる。
これらは勝手に設定されて、変更できなさそう。(調査不足)

ソリューション
    |- SampleProj   ※C#プロジェクト名
        |- Properties
            |- aiueo.wav ※音声データ1
            |- dindon.mp3 ※音声データ2
            |- Resources.resx
                |- Resources.Designer.cs
...

登録したリソースは、次のように自動的に実装が作られる。リソースの名前や定義に、拡張子は含まれないようだ。
これらのリソース定義を使用しても良いし、自分でResourceManagerを使って取得しても良い。リソース定義を使った場合は、wav(オーディオ)はstreamで、mp3(ファイル)はbyte[]で取得できる。
以下では、リソースをstring等で選ぶことを考えて、自分でResourceManagerを使って取得する方法で記述している。

Resources.Designer.cs
namespace SampleProj.Properties {
    // ...省略...
    internal static System.IO.UnmanagedMemoryStream aiueo {
        get {
            return ResourceManager.GetStream("aiueo", resourceCulture);
        }
    }

    internal static byte[] dindon {
        get {
            object obj = ResourceManager.GetObject("dindon", resourceCulture);
            return ((byte[])(obj));
        }
    }
}

PlaySoundによるwavの再生

winmm.dllからPlaySoundをインポートする。
引数で渡す予定のFlagも、別途enumで定義しておく。

[DllImport("winmm.dll", CharSet = CharSet.Auto)]
private static extern bool PlaySound(byte[] sound, IntPtr hMod, PlaySoundFlags flags);

[System.Flags]
public enum PlaySoundFlags : int
{
    SND_MEMORY = 0x0004,  // メモリの再生の意
}

再生はPlaySoundにbyte配列を渡すことで行える。
オーディオリソースはstreamなので、いったん別のbyte配列に読み込む。

using var target = SampleProj.Properties.Resources.ResourceManager.GetStream("aiueo");
byte[] buffer = new byte[target.Length];
target.Read(buffer, 0, buffer.Length);
target.Close();
// 再生
_ = PlaySound(buffer, IntPtr.Zero, PlaySoundFlags.SND_MEMORY);

停止も同じAPIで、第一引数をnullに、第三引数を0にする。これ以上のPlaySoundの利用方法は省略。

// 停止
_ = PlaySound(null, IntPtr.Zero, 0);

NAudioによるmp3の再生

NAudioは次で配布されているMs-PLライセンスの、.NET向け音声再生APIである。dll一つで扱える簡単さでありながら様々な音声形式に対応する。wav形式も対応しているので、PlaySoundではなくNAudioを使うこともできる。
https://github.com/naudio/NAudio

再生は、NAudioのAPIであるMp3FileReaderMemoryStreamを渡すことで行う。
再生状態はWaveOut.PlaybackStateで判別できる。これをnowaitでポーリングすると音声再生が乱れたのでwaitを入れている。多分ちゃんと調べる方法はある。(調査不足)

// WaveOutのインスタンスはクラスフィールドで持つなりする。
var player = new NAudio.Wave.WaveOut();  // 要Dispose

// リソースからデータの取得
byte[] buffer = (byte[])Properties.Resources.ResourceManager.GetObject("dindon");
using var stream = new MemoryStream(buffer)
{
    Position = 0  // 先頭位置からの再生を意味するが、streamを新規にnewするときは不要なはず
};
using WaveStream pcm = new Mp3FileReader(stream);
player.Init(pcm);
// 再生
player.Play();

// 待ち(ここ調査不足)
while (player.PlaybackState == PlaybackState.Playing)
{
    await Task.Delay(10);
}

停止はWaveOut.Stop()で行える。

// 停止
player.Stop();

まとめ

exe単体ないしはdllの同梱のみで、音声データを再生する方法を調べた。
とにかく再生できれば良かったので、再生中かどうかを考慮したり音声デバイスを選んだりなどは本記事では省略している。

  • リソースで埋め込んだwave形式とmp3形式のデータを再生する
  • PlaySoundとNAudioの2つの方法で再生する
5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?