その2で書いた通り、次は録音ですね。
※下記サイトを参考にさせて頂きました。感謝です。
Managed DirectSoundを使ってマイクから音声を録音してみる2
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Runtime.InteropServices; using System.Threading; using System.IO; using System.Windows.Forms; using System.Diagnostics; using Microsoft.DirectX; using Microsoft.DirectX.DirectSound; namespace Sample2 { public class CaptureSound : IDisposable { private WaveFormat fmt; private string file_path; private bool isRecording; private Device device; private Capture capture; private int notifySize; private static int notifyPos = 0; private const int NUMBER_RECORD_NOTIFICATIONS = 16; private BufferPositionNotify[] PositionNotify = new BufferPositionNotify[NUMBER_RECORD_NOTIFICATIONS]; private CaptureBuffer captureBuffer; CaptureBufferDescription captureBufferDescription; private Thread notifyThread; private AutoResetEvent autoResetEvent; private Notify notify; BinaryWriter binaryWriter; private int dataLength = 0; // コンストラクタ public CaptureSound () { this.fmt = new WaveFormat(); this.fmt.FormatTag = WaveFormatTag.Pcm; this.fmt.SamplesPerSecond = 44100; this.fmt.BitsPerSample = 16; this.fmt.Channels = 1; this.fmt.BlockAlign = (short)(this.fmt.Channels * (this.fmt.BitsPerSample / (short)8)); this.fmt.AverageBytesPerSecond = this.fmt.BlockAlign * this.fmt.SamplesPerSecond; this.isRecording = false; this.file_path = @"C:\Sample2\dummy.wav"; } // 録音開始(ボタンクリック時など。'owner'は呼び出し元フォームなど。 public bool startRecord(Form owner) { if (isRecording) { return false; } this.device = new Device(); this.device.SetCooperativeLevel(owner, CooperativeLevel.Priority); CaptureDevicesCollection capDev = new CaptureDevicesCollection(); Guid cap_guid = getGuid(capDev); if (Guid.Empty == cap_guid) { return "録音デバイスがありません。"; } this.capture = new Capture(cap_guid); this.isRecording = true; RecWave(); CreateCapBuffer(); this.captureBuffer.Start(true); return true; } // *.wavファイルのヘッダー部分を書く private void RecWave() { 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 = (short)this.fmt.FormatTag; int formatLength = 0x10; int length = 0; short shBytePerSample = (short)((this.fmt.BitsPerSample / (short)8) * this.fmt.Channels); try { this.binaryWriter = new BinaryWriter(new FileStream(this.file_path, FileMode.Create)); this.binaryWriter.Write(Riff); this.binaryWriter.Write(length); this.binaryWriter.Write(Wave); this.binaryWriter.Write(Fmt); this.binaryWriter.Write(formatLength); this.binaryWriter.Write(padding); this.binaryWriter.Write(this.fmt.Channels); this.binaryWriter.Write(this.fmt.SamplesPerSecond); this.binaryWriter.Write(this.fmt.AverageBytesPerSecond); this.binaryWriter.Write(shBytePerSample); this.binaryWriter.Write(this.fmt.BitsPerSample); this.binaryWriter.Write(Data); this.binaryWriter.Write((int)0); } catch (Exception e) { MessageBox.Show(e.Message); } } // キャプチャバッファの作成 void CreateCapBuffer() { this.notifySize = this.fmt.AverageBytesPerSecond / NUMBER_RECORD_NOTIFICATIONS; this.notifySize -= this.notifySize % this.fmt.BlockAlign; try { this.captureBufferDescription = new CaptureBufferDescription(); this.captureBufferDescription.BufferBytes = notifySize * NUMBER_RECORD_NOTIFICATIONS; //waveFormat.AverageBytesPerSecond; this.captureBufferDescription.WaveMapped = false; this.captureBufferDescription.ControlEffects = false; this.captureBufferDescription.Format = this.fmt; this.captureBuffer = new CaptureBuffer(this.captureBufferDescription, this.capture); } catch (BadFormatException e) { MessageBox.Show(e.ErrorString); return; } // RecWave(); notifyThread = new Thread(new ThreadStart(CapThreadProc)); notifyThread.Start(); this.autoResetEvent = new AutoResetEvent(false); this.notify = new Notify(this.captureBuffer); for (int i = 0; i < NUMBER_RECORD_NOTIFICATIONS; i++) { PositionNotify[i].Offset = this.notifySize * (i + 1) - 1; PositionNotify[i].EventNotifyHandle = this.autoResetEvent.Handle; } notify.SetNotificationPositions(PositionNotify, NUMBER_RECORD_NOTIFICATIONS); } // 実際に音声をキャプチャして、*.wavファイルのデータ部分に書き出す処理 public void CapThreadProc() { // Debug.WriteLine(this.isRecording.ToString()); while (this.isRecording) { this.autoResetEvent.WaitOne(Timeout.Infinite, true); int offset = 0; int readPos, capturePos; this.captureBuffer.GetCurrentPosition(out capturePos, out readPos); int lockSize = this.notifySize - offset; capturePos = this.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); this.binaryWriter.Write(captureData, 0, captureData.Length); this.dataLength += captureData.Length; notifyPos++; notifyPos %= NUMBER_RECORD_NOTIFICATIONS; } } // 「プライマリ・デバイス」以外の録音デバイスのGUIDを取得する private Guid getGuid(CaptureDevicesCollection _capDev) { for (int i = 0; i < _capDev.Count; i++) { Guid c_guid = _capDev[i].DriverGuid; string c_description = _capDev[i].Description; if (c_guid != System.Guid.Empty && c_description != "") { return c_guid; } } return Guid.Empty; } // 録音停止処理 public void stopRecord() { if (!this.isRecording) { MessageBox.Show("録音していません。", Define.CLASS_NAME); return; } this.captureBuffer.Stop(); this.notifyThread.Abort(); // *.wavファイルのヘッダー部分の「ファイルサイズ - 8」を書き込む処理 int dataSizeMinusEight = this.dataLength + 44 - 8; this.binaryWriter.Seek(4, SeekOrigin.Begin); this.binaryWriter.Write(dataSizeMinusEight); // *.wavファイルのヘッダー部分の「実データのサイズ」を書き込む処理 this.binaryWriter.Seek(40, SeekOrigin.Begin); this.binaryWriter.Write(this.dataLength); this.binaryWriter.Close(); this.isRecording = false; MessageBox.Show("録音終了。", Define.CLASS_NAME); } // 録音中かどうかのフラグを返す(呼び出し元フォーム等で使用する) public Boolean getIsRecording() { return this.isRecording; } // デストラクタ public void Dispose() { } } }
しかし、コーディング技法というか、リーダブルなコードの書き方、もっと勉強しなくては…
この本は買って、読んでいるんだけど…
リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)