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イベントハンドラを追加する必要があります。
稚拙な説明で解りづらくて申し訳ないです。。。
自分はまだまだ勉強中の身で、まだ動いたというレベルなので
こんな汚いソースですが、何かのお役に立てれば幸いです。