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」を参考にさせて頂きました。

    • k-1
    • 2012 06/10 6:22pm

    作られたプログラムのコンパイルと実行はできたのですが、何もないウィンドウだけが出てきます。
    どう操作すれば良いのでしょうか?

      • chakemi
      • 2012 06/11 9:47pm

      はじめまして。
      ご覧頂きありがとうございます。

      ウィンドウにボタンは表示されていないでしょうか?

      ボタンが表示されていないのでしたら、
      フォームデザイナでButtonコンポーネントを配置し、button1_Clickイベントハンドラを追加してください。
      button1_Clickイベントハンドラメソッドで録音の開始、停止を行なってます。

      また、このサンプルではフォーム起動時にもForm1_Loadイベントハンドラメソッドを実行するように書いてますので
      同じくフォームデザイナでForm1_Loadイベントハンドラを追加する必要があります。

      稚拙な説明で解りづらくて申し訳ないです。。。

      自分はまだまだ勉強中の身で、まだ動いたというレベルなので
      こんな汚いソースですが、何かのお役に立てれば幸いです。

return top