SewiGの日記
2006-06-24 [土]
■ [C#][Programming] C#でサウンド(4)
Win32APIのwaveOutやPlaySoundを使う
まず、PlaySound。音関連はwinmm.dllにあるので、DllImportを使います。
[DllImport("winmm.dll")] extern static int PlaySound(string str, IntPtr ip1, int ip2);
このextern〜で使いたいメソッドが外部に定義されているよ、と教えておきます。
それから、使いそうな定数もあらかじめ調べておきます。
private const int SND_SYNC = 0x00000; private const int SND_ASYNC = 0x00001; private const int SND_LOOP = 0x00008; private const int SND_FILENAME = 0x20000; private const int SND_RESOURCE = 0x40004;
まとめると、以下のような感じでしょうか。
using System; using System.Runtime.InteropServices; namespace Sample { public class SndPlay { [DllImport("winmm.dll")] extern static int PlaySound(string str, IntPtr ip1, int i2); private const int SND_SYNC = 0x00000; private const int SND_ASYNC = 0x00001; private const int SND_LOOP = 0x00008; private const int SND_FILENAME = 0x20000; private const int SND_RESOURCE = 0x40004; public void play(string filename) { PlaySound(filename, IntPtr.Zero, SND_FILENAME|SND_ASYNC); } public void stop() { PlaySound(null, IntPtr.Zero, 0); } } }
で、waveOutですが、これが面倒。面倒だけど音をミックスして出力したり、ストリーム再生できたりと便利。そこで、Interop Declarations for Windows.hを利用することで、Win32プログラミングっぽいことをC#で可能にします。しかし、ポインタを使わざるをえません。そしてそれに伴ってunsafeの指定が必要になります。とりあえず、サイン波でも鳴らしてみましょう。こちらのページは今現在日本語で書いてある数少ない参考ページです。
というか、ほとんど一緒。
using System; using System.Runtime.InteropServices; using System.Windows.Forms; namespace Sample { public class WavePlay { unsafe public void play() { // 波形生成 short *wave_data = stackalloc short[44100]; double dr = 2 * Math.PI / (44100.0 / 440.0); for (int t = 0; t < 44100; t++) { *(wave_data + t) = (short)(Math.Sin(dr * t) * 32767); } // WAVEデバイス設定 WAVEFORMATEX wf = new WAVEFORMATEX(); wf.wFormatTag = 0x0001; // PCM wf.nChannels = 1; // モノラル wf.nSamplesPerSec = 44100; // 周波数 wf.wBitsPerSample = 16; // 16bit wf.nBlockAlign = (ushort)(wf.nChannels * wf.wBitsPerSample / 8); wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign; wf.cbSize = 0; HWAVEOUT__ hwo = new HWAVEOUT__(); HWAVEOUT__ *hWOut = &hwo; windows.waveOutOpen(&hWOut, 0x0000, &wf, 0, 0, 0x0000); // WAVE情報設定 wavehdr_tag wt = new wavehdr_tag(); wt.lpData = (sbyte *)wave_data; wt.dwBufferLength = sizeof(short) * 44100; wt.dwFlags = 0; //バッファの追加情報 wt.dwLoops = 1; //1回再生 wt.dwBytesRecorded = 0; //録音用 wt.dwUser = 0; //オプションのユーザ領域 wt.lpNext = null; //使用しない wt.reserved = 0; //使用しない windows.waveOutPrepareHeader(hWOut, &wt, (uint)sizeof(wavehdr_tag)); windows.waveOutWrite(hWOut, &wt, (uint)sizeof(wavehdr_tag)); MessageBox.Show("OK", "確認", MessageBoxButtons.OK); windows.waveOutClose(hWOut); } } }
何か、もうC#じゃないみたい。
簡単に動作説明すると、waveOutOpen()で再生デバイスを開きます。ウェーブの情報はWAVEHDRに書き込みます。生のウェーブデータは適当な配列を用意します。waveOutWrite()で出力します。使い終わったらwaveOutClose()で閉じます。基本は、オープンしたら、データのセット→バッファの準備→バッファの書き込みの繰り返しです。このウェーブバッファの循環によって途切れなく再生が可能になり、また動的な制御に強い理由です。
● Rxvxrahd [If it was more on Assignment on the main highlights is the..]