一.声卡录音的基本原理
为了实现一个录音的基本过程,至少需要以下对象的支持:
1. 录音设备,对我们的PC设备就是声卡。这个录音设备可以进行的操作应该有开始和关闭。
2. 缓冲区,也就是录制的声音放在哪里的问题。
二.DirectSound对录音的描述模型
1. DirectSound对录音的支持类
Capture,设备对象,可以看作是声卡的描述。
CaptureBuffer,缓冲区对象,存放录入的音频数据。
Notify,事件通知对象,由于录音是一个长时间的过程,因此使用一个缓冲队列(多个缓冲区)接收数据,每当一个缓冲区满的时候,系统使用这个对象通知应用程序取走这个缓冲区,并继续录音。
以上三个对象是进行录音操作的主要对象,由于在C++中对DirectSound的操作DirectX帮助文档中已经有很详细的说明,这里就不再赘述了。本文是针对Managed Code。除了以上三个主要的DirectSound类,还需要以下几个辅助类。
WaveFormat,描述了进行录制的声音波形的格式,例如采样率,单声道还是立体声,每个采样点的长度等等。
Thread,线程类,由于录音的过程是需要不断处理缓冲区满的事件,因此新建一个线程对此进行单独处理。
AutoResetEvent,通知的事件,当缓冲区满的时候,使用该事件作为通知事件。
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.IO;
5using System.Windows.Forms;
6using System.Threading;
7using Microsoft.DirectX;
8using Microsoft.DirectX.DirectSound;
9namespace pcd.DirectSound
10{
11 /// <summary>
12 /// 录音
13 /// </summary>
14 public class SoundRecord
15 {
16 //SoundRecord的成员数据
17 public const int cNotifyNum = 16; // 缓冲队列的数目
18 private int mNextCaptureOffset = 0; // 该次录音缓冲区的起始点
19 private int mSampleCount = 0; // 录制的样本数目
20 private int mNotifySize = 0; // 每次通知大小
21 private int mBufferSize = 0; // 缓冲队列大小
22 private string mFileName = string.Empty; // 文件名
23 private FileStream mWaveFile = null; // 文件流
24 private BinaryWriter mWriter = null; // 写文件
25 private Capture mCapDev = null; // 音频捕捉设备
26 private CaptureBuffer mRecBuffer = null; // 缓冲区对象
27 private Notify mNotify = null; // 消息通知对象
28 private WaveFormat mWavFormat; // 录音的格式
29 private Thread mNotifyThread = null; // 处理缓冲区消息的线程
30 private AutoResetEvent mNotificationEvent = null; // 通知事件
31
32 构造函数 构造函数
33 /// <summary>
34 /// 构造函数,设定录音设备,设定录音格式.
35 /// </summary>
36 public SoundRecord()
37 {
38 // 初始化音频捕捉设备
39 InitCaptureDevice();
40 // 设定录音格式
41 mWavFormat = CreateWaveFormat();
42 }
43 #endregion
44
45 公开方法 公开方法
46 /// <summary>
47 /// 设定录音结束后保存的文件,包括路径
48 /// </summary>
49 /// <param name="filename">保存wav文件的路径名</param>
50 public void SetFileName(string filename)
51 {
52 mFileName = filename;
53 }
54 /// <summary>
55 /// 开始录音
56 /// </summary>
57 public void RecStart()
58 {
59
60 // 创建录音文件
61 CreateSoundFile();
62 // 创建一个录音缓冲区,并开始录音
63 CreateCaptureBuffer();
64 // 建立通知消息,当缓冲区满的时候处理方法
65 InitNotifications();
66 mRecBuffer.Start(true);
67 }
68
69 /// <summary>
70 /// 停止录音
71 /// </summary>
72 public void RecStop()
73 {
74 try
75 {
76 // 关闭通知消息
77 if (null != mNotificationEvent)
78 mNotificationEvent.Set();
79 // 停止录音
80 mRecBuffer.Stop();
81 // 写入缓冲区最后的数据
82 RecordCapturedData();
83 // 回写长度信息
84 mWriter.Seek(4, SeekOrigin.Begin);
85 mWriter.Write((int)(mSampleCount + 36)); // 写文件长度
86 mWriter.Seek(40, SeekOrigin.Begin);
87 mWriter.Write(mSampleCount); // 写数据长度
88 mWriter.Close();
89 mWaveFile.Close();
90 mWriter = null;
91 mWaveFile = null;
92 }
93 catch
94 { }
95 }
96 #endregion
97
98 内部调用函数 内部调用函数
99 /// <summary>
100 /// 初始化录音设备,此处使用主录音设备.
101 /// </summary>
102 /// <returns>调用成功返回true,否则返回false</returns>
103 private bool InitCaptureDevice()
104 {
105 // 获取默认音频捕捉设备
106 CaptureDevicesCollection devices = new CaptureDevicesCollection(); // 枚举音频捕捉设备
107 Guid deviceGuid = Guid.Empty; // 音频捕捉设备的ID
108 if (devices.Count > 0)
109 deviceGuid = devices[0].DriverGuid;
110 else
111 {
112 MessageBox.Show("系统中没有音频捕捉设备");
113 return false;
114 }
115 // 用指定的捕捉设备创建Capture对象
116 try
117 {
118 mCapDev = new Capture(deviceGuid);
119 }
120 catch (DirectXException e)
121 {
122 MessageBox.Show(e.ToString());
123 return false;
124 }
125 return true;
126 }
127 /// <summary>
128
129 /// 创建录音格式,此处使用16bit,16KHz,Mono的录音格式
130 /// </summary>
131 /// <returns>WaveFormat结构体</returns>
132 private WaveFormat CreateWaveFormat()
133 {
134 WaveFormat format = new WaveFormat();
135 format.FormatTag = WaveFormatTag.Pcm; // PCM
136 format.SamplesPerSecond = 16000; // 16KHz
137 format.BitsPerSample = 16; // 16Bit
138 format.Channels = 1; // Mono
139 format.BlockAlign = (short)(format.Channels * (format.BitsPerSample / 8));
140 format.AverageBytesPerSecond = format.BlockAlign * format.SamplesPerSecond;
141 return format;
142 }
143 /// <summary>
144 /// 创建录音使用的缓冲区
145 /// </summary>
146 private void CreateCaptureBuffer()
147 {
148 // 缓冲区的描述对象
149 CaptureBufferDescription bufferdescription = new CaptureBufferDescription();
150 if (null != mNotify)
151 {
152 mNotify.Dispose();
153 mNotify = null;
154 }
155 if (null != mRecBuffer)
156 {
157 mRecBuffer.Dispose();
158 mRecBuffer = null;
159 }
160 // 设定通知的大小,默认为1s钟
161