Managed DirectSoundを使ってマイクから音声を録音してみる2
chakemiです。予想通り風邪を引いてしまいました。。。喉が痛い。。。
そんな中、本日は、前回未完成に終わったManaged DirectSoundを使ってマイクから音声のキャプチャですが、とりあえず、どうにか動くとこまで出来ました。
開発環境:
WindowsXP SP3
VisualC#2010Express
前回、大まかにWaveFormatの生成、Device情報から、Captureオブジェクトの作成、captureBufferDescriptionインスタンスの生成まで書きました。
今回はこれらをもとに、CaptureBufferインスタンスを生成し
captureBuffer = new CaptureBuffer(captureBufferDescription, capture);
バッファの更新の通知を登録します。
autoResetEvent = new AutoResetEvent(false); notify = new Notify(captureBuffer); for (int i = 0; i < NumberRecordNotifications; i++) { PositionNotify[i].Offset = notifySize * (i + 1) - 1; PositionNotify[i].EventNotifyHandle = autoResetEvent.Handle; } notify.SetNotificationPositions(PositionNotify, NumberRecordNotifications);
別スレッドでイベント通知を待って、
public void CapThreadProc() { while (capflag) { autoResetEvent.WaitOne(Timeout.Infinite, true); int offset = 0; int readPos, capturePos; captureBuffer.GetCurrentPosition(out capturePos, out readPos); int lockSize = notifySize - offset; capturePos = notifySize * notifyPos; if (lockSize < 0) lockSize += captureBufferDescription.BufferBytes; lockSize -= (lockSize % 2); if (0 == lockSize) return;
キャプチャされたデータを取得して、書き込みます。
byte[] captureData = (byte[])captureBuffer.Read(capturePos, typeof(byte), LockFlag.None, lockSize); binaryWriter.Write(captureData, 0, captureData.Length); notifyPos++; notifyPos %= NumberRecordNotifications; } }
以下、ソース全体。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO; using Microsoft.DirectX; using Microsoft.DirectX.DirectSound; using System.Threading; namespace testDirectSound2 { public partial class Form1 : Form { private WaveFormat waveFormat; private Device device; private CaptureDevicesCollection captureDevice; private Capture capture; private CaptureBuffer captureBuffer; private CaptureBufferDescription captureBufferDescription; private BinaryWriter binaryWriter; private AutoResetEvent autoResetEvent; private Notify notify; private Thread notifyThread; private int notifySize = 0; private static int notifyPos = 0; private const int NumberRecordNotifications = 16; private BufferPositionNotify[] PositionNotify = new BufferPositionNotify[NumberRecordNotifications]; private bool capflag = false; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { waveFormat = new WaveFormat(); waveFormat.Channels = 1; waveFormat.FormatTag = WaveFormatTag.Pcm; waveFormat.BitsPerSample = 16; waveFormat.SamplesPerSecond = 44100; waveFormat.BlockAlign = (short)(waveFormat.Channels * (waveFormat.BitsPerSample / (short)8)); waveFormat.AverageBytesPerSecond = waveFormat.BlockAlign * waveFormat.SamplesPerSecond; device = new Device(); device.SetCooperativeLevel(this, CooperativeLevel.Priority); captureDevice = new CaptureDevicesCollection(); DeviceInformation deviceInfo = captureDevice[0]; capture = new Capture(deviceInfo.DriverGuid); } private void button1_Click(object sender, EventArgs e) { capflag = !capflag; if (capflag) { RecWave(); CreateCapBuffer(); captureBuffer.Start(true); } else { captureBuffer.Stop(); notifyThread.Abort(); } } void CreateCapBuffer() { notifySize = waveFormat.AverageBytesPerSecond / NumberRecordNotifications; notifySize -= notifySize % waveFormat.BlockAlign; try { captureBufferDescription = new CaptureBufferDescription(); captureBufferDescription.BufferBytes = notifySize * NumberRecordNotifications;//waveFormat.AverageBytesPerSecond; captureBufferDescription.WaveMapped = false; captureBufferDescription.ControlEffects = false; captureBufferDescription.Format = waveFormat; captureBuffer = new CaptureBuffer(captureBufferDescription, capture); } catch (Exception ex) { throw ex; } //RecWave(); notifyThread = new Thread(new ThreadStart(CapThreadProc)); notifyThread.Start(); autoResetEvent = new AutoResetEvent(false); notify = new Notify(captureBuffer); for (int i = 0; i < NumberRecordNotifications; i++) { PositionNotify[i].Offset = notifySize * (i + 1) - 1; PositionNotify[i].EventNotifyHandle = autoResetEvent.Handle; } notify.SetNotificationPositions(PositionNotify, NumberRecordNotifications); } void RecWave() { binaryWriter = new BinaryWriter(new FileStream(@"C:\test_ds_rec.wav", FileMode.Create)); char[] Riff = { 'R', 'I', 'F', 'F' }; char[] Wave = { 'W', 'A', 'V', 'E' }; char[] Fmt = { 'f', 'm', 't', ' ' }; char[] Data = { 'd', 'a', 't', 'a' }; short padding = 1; int formatLength = 0x10; int length = 0; short shBytePerSample = 2; binaryWriter.Write(Riff); binaryWriter.Write(length); binaryWriter.Write(Wave); binaryWriter.Write(Fmt); binaryWriter.Write(formatLength); binaryWriter.Write(padding); binaryWriter.Write(waveFormat.Channels); binaryWriter.Write(waveFormat.SamplesPerSecond); binaryWriter.Write(waveFormat.AverageBytesPerSecond); binaryWriter.Write(shBytePerSample); binaryWriter.Write(waveFormat.BitsPerSample); binaryWriter.Write(Data); binaryWriter.Write((int)0); } public void CapThreadProc() { while (capflag) { autoResetEvent.WaitOne(Timeout.Infinite, true); int offset = 0; int readPos, capturePos; captureBuffer.GetCurrentPosition(out capturePos, out readPos); int lockSize = notifySize - offset; capturePos = notifySize * notifyPos; if (lockSize < 0) lockSize += captureBufferDescription.BufferBytes; lockSize -= (lockSize % 2); if (0 == lockSize) return; byte[] captureData = (byte[])captureBuffer.Read(capturePos, typeof(byte), LockFlag.None, lockSize); binaryWriter.Write(captureData, 0, captureData.Length); notifyPos++; notifyPos %= NumberRecordNotifications; } } } }
まだまだ、動いたというレベルで完全に理解出来ていないので、引き続き勉強しようと思います。
今回、こちらのサイトと、サンプルの「CaptureSound」を参考にさせて頂きました。
作られたプログラムのコンパイルと実行はできたのですが、何もないウィンドウだけが出てきます。
どう操作すれば良いのでしょうか?
はじめまして。
ご覧頂きありがとうございます。
ウィンドウにボタンは表示されていないでしょうか?
ボタンが表示されていないのでしたら、
フォームデザイナでButtonコンポーネントを配置し、button1_Clickイベントハンドラを追加してください。
button1_Clickイベントハンドラメソッドで録音の開始、停止を行なってます。
また、このサンプルではフォーム起動時にもForm1_Loadイベントハンドラメソッドを実行するように書いてますので
同じくフォームデザイナでForm1_Loadイベントハンドラを追加する必要があります。
稚拙な説明で解りづらくて申し訳ないです。。。
自分はまだまだ勉強中の身で、まだ動いたというレベルなので
こんな汚いソースですが、何かのお役に立てれば幸いです。