C#中使用DirectSound录音
来源:互联网 发布:淘宝迟迟不发货骗局 编辑:程序博客网 时间:2024/06/04 17:50
原文地址:http://blog.donews.com/uplook/archive/2005/12/14/657145.aspx
注:1.原文有程序终止后仍有线程在运行的情况,这里修正了下;
2.DirectSound录音详细介绍:http://blog.csdn.net/woaixiaozhe/article/details/7863007
3."Mixed mode assembly is built against version 'v1.1.4322' of the runtime and......"问题解决方案见:http://blog.csdn.net/woaixiaozhe/article/details/7864391
一.声卡录音的基本原理
为了实现一个录音的基本过程,至少需要以下对象的支持:
1. 录音设备,对我们的PC设备就是声卡。这个录音设备可以进行的操作应该有开始和关闭。
2. 缓冲区,也就是录制的声音放在哪里的问题。
二.DirectSound对录音的描述模型
1. DirectSound对录音的支持类
Ø Capture,设备对象,可以看作是声卡的描述。
Ø CaptureBuffer,缓冲区对象,存放录入的音频数据。
Ø Notify,事件通知对象,由于录音是一个长时间的过程,因此使用一个缓冲队列(多个缓冲区)接收数据,每当一个缓冲区满的时候,系统使用这个对象通知应用程序取走这个缓冲区,并继续录音。
以上三个对象是进行录音操作的主要对象,由于在C++中对DirectSound的操作DirectX帮助文档中已经有很详细的说明,这里就不再赘述了。本文是针对Managed Code。除了以上三个主要的DirectSound类,还需要以下几个辅助类。
Ø WaveFormat,描述了进行录制的声音波形的格式,例如采样率,单声道还是立体声,每个采样点的长度等等。
Ø Thread,线程类,由于录音的过程是需要不断处理缓冲区满的事件,因此新建一个线程对此进行单独处理。
Ø AutoResetEvent,通知的事件,当缓冲区满的时候,使用该事件作为通知事件。
三.代码解析(SoundRecord类)
1.需要引用的程序集
- #region 成员数据
- private Capture mCapDev = null;
- private CaptureBuffer mRecBuffer = null;
- private WaveFormat mWavFormat;
-
- private int mNextCaptureOffset = 0;
- private int mSampleCount = 0;
-
- private Notify mNotify = null;
- public const int cNotifyNum = 16;
- private int mNotifySize = 0;
- private int mBufferSize = 0;
- private Thread mNotifyThread = null;
- private AutoResetEvent mNotificationEvent = null;
-
- private string mFileName = string.Empty;
- private FileStream mWaveFile = null;
- private BinaryWriter mWriter = null;
- #endregion
3. 对外操作的函数- #region 对外操作函数
-
-
-
- public SoundRecorder()
- {
-
- InitCaptureDevice();
-
- mWavFormat = CreateWaveFormat();
- }
-
-
-
-
- private WaveFormat CreateWaveFormat()
- {
- WaveFormat format = new WaveFormat();
- format.FormatTag = WaveFormatTag.Pcm;
- format.SamplesPerSecond = 16000;
- format.BitsPerSample = 16;
- format.Channels = 1;
- format.BlockAlign = (short)(format.Channels * (format.BitsPerSample / 8));
- format.AverageBytesPerSecond = format.BlockAlign * format.SamplesPerSecond;
- return format;
-
- }
-
-
-
-
-
- public void SetFileName(string filename)
- {
- mFileName = filename;
- }
-
-
-
-
- public void RecStart()
- {
-
- CreateSoundFile();
-
- CreateCaptureBuffer();
-
- InitNotifications();
- mRecBuffer.Start(true);
- }
-
-
-
-
-
- public void RecStop()
- {
- mRecBuffer.Stop();
- if (null != mNotificationEvent)
- mNotificationEvent.Set();
- mNotifyThread.Abort();
- RecordCapturedData();
-
-
- mWriter.Seek(4, SeekOrigin.Begin);
- mWriter.Write((int)(mSampleCount + 36));
- mWriter.Seek(40, SeekOrigin.Begin);
- mWriter.Write(mSampleCount);
-
- mWriter.Close();
- mWaveFile.Close();
- mWriter = null;
- mWaveFile = null;
- }
- dregion
4.内部调用函数- #region 对内操作函数
-
-
-
-
- private bool InitCaptureDevice()
- {
-
- CaptureDevicesCollection devices = new CaptureDevicesCollection();
- Guid deviceGuid = Guid.Empty;
-
- if (devices.Count>0)
- deviceGuid = devices[0].DriverGuid;
- else
- {
- MessageBox.Show("系统中没有音频捕捉设备");
- return false;
- }
-
-
- try
- {
- mCapDev = new Capture(deviceGuid);
- }
- catch (DirectXException e)
- {
- MessageBox.Show(e.ToString());
- return false;
- }
- return true;
- }
-
-
-
-
- private void CreateCaptureBuffer()
- {
-
- CaptureBufferDescription bufferdescription = new CaptureBufferDescription();
- if (null != mNotify)
- {
- mNotify.Dispose();
- mNotify = null;
- }
- if (null != mRecBuffer)
- {
- mRecBuffer.Dispose();
- mRecBuffer = null;
- }
-
- mNotifySize = (1024 > mWavFormat.AverageBytesPerSecond/8) ? 1024 : (mWavFormat.AverageBytesPerSecond / 8);
- mNotifySize -= mNotifySize % mWavFormat.BlockAlign;
-
- mBufferSize = mNotifySize * cNotifyNum;
-
- bufferdescription.BufferBytes = mBufferSize;
- bufferdescription.Format = mWavFormat;
-
- mRecBuffer = new CaptureBuffer(bufferdescription, mCapDev);
- mNextCaptureOffset = 0;
- }
-
-
-
-
-
- private bool InitNotifications()
- {
- if (null == mRecBuffer)
- {
- MessageBox.Show("未创建录音缓冲区");
- return false;
- }
-
- mNotificationEvent = new AutoResetEvent(false);
-
- if (null == mNotifyThread)
- {
- mNotifyThread = new Thread(new ThreadStart(WaitThread));
- mNotifyThread.Start();
- }
-
- BufferPositionNotify[] PositionNotify = new BufferPositionNotify[cNotifyNum + 1];
- for (int i = 0; i < cNotifyNum; i++)
- {
- PositionNotify[i].Offset = (mNotifySize * i) + mNotifySize - 1;
- PositionNotify[i].EventNotifyHandle = mNotificationEvent.SafeWaitHandle.DangerousGetHandle();
- }
- mNotify = new Notify(mRecBuffer);
- mNotify.SetNotificationPositions(PositionNotify, cNotifyNum);
- return true;
- }
-
-
-
-
- private void WaitThread()
- {
- while (true)
- {
-
- mNotificationEvent.WaitOne(Timeout.Infinite, true);
-
- RecordCapturedData();
- }
- }
-
-
-
-
- private void RecordCapturedData()
- {
- byte[] CaptureData = null;
- int ReadPos=0, CapturePos=0, LockSize=0;
- mRecBuffer.GetCurrentPosition(out CapturePos, out ReadPos);
- LockSize = ReadPos - mNextCaptureOffset;
- if (LockSize < 0)
- LockSize += mBufferSize;
- LockSize -= (LockSize % mNotifySize);
- if (0 == LockSize)
- return;
-
-
- CaptureData = (byte[])mRecBuffer.Read(mNextCaptureOffset, typeof(byte), LockFlag.None, LockSize);
-
- mWriter.Write(CaptureData, 0, CaptureData.Length);
-
- mSampleCount += CaptureData.Length;
-
- mNextCaptureOffset += CaptureData.Length;
- mNextCaptureOffset %= mBufferSize;
- }
-
-
-
-
- private void CreateSoundFile()
- {
-
- mWaveFile = new FileStream(mFileName, FileMode.Create);
- mWriter = new BinaryWriter(mWaveFile);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- char[] ChunkRiff = {'R', 'I','F','F'};
- char[] ChunkType = {'W','A','V','E'};
- char[] ChunkFmt = {'f','m','t',' '};
- char[] ChunkData = {'d','a','t','a'};
-
- short shPad = 1;
- int nFormatChunkLength = 0x10;
- int nLength = 0;
- short shBytesPerSample = 0;
-
-
- if (8 == mWavFormat.BitsPerSample && 1 == mWavFormat.Channels)
- shBytesPerSample = 1;
- else if ((8 == mWavFormat.BitsPerSample && 2 == mWavFormat.Channels) || (16 == mWavFormat.BitsPerSample && 1 == mWavFormat.Channels))
- shBytesPerSample = 2;
- else if (16 == mWavFormat.BitsPerSample && 2 == mWavFormat.Channels)
- shBytesPerSample = 4;
-
-
- mWriter.Write(ChunkRiff);
- mWriter.Write(nLength);
- mWriter.Write(ChunkType);
-
-
- mWriter.Write(ChunkFmt);
- mWriter.Write(nFormatChunkLength);
- mWriter.Write(shPad);
- mWriter.Write(mWavFormat.Channels);
- mWriter.Write(mWavFormat.SamplesPerSecond);
- mWriter.Write(mWavFormat.AverageBytesPerSecond);
- mWriter.Write(shBytesPerSample);
- mWriter.Write(mWavFormat.BitsPerSample);
-
-
- mWriter.Write(ChunkData);
- mWriter.Write((int)0);
- }
- #endregion
5.外部窗体调用方式
声明部分:
- private SoundRecord recorder = null;
窗体构造函数:- recorder = new SoundRecord();
启动录音按钮:- private void btnStart_Click(object sender, System.EventArgs e)
- {
-
-
-
- string wavfile = null;
- wavfile = “test.wav”;
- recorder.SetFileName(wavfile);
- recorder.RecStart();
- }
中止录音按钮:- private void btnStop_Click(object sender, System.EventArgs e)
- {
- recorder.RecStop();
- recorder = null;
- }
6.需要添加的外部引用文件
在系统的System32目录下添加以下两个引用文件,如果没有,在DirectX的开发包内可以找到。
Microsoft.DirectX.dll
Microsoft.DirectX.DirectSound.dll
评论也贴过来吧:
转自:http://blog.csdn.net/woaixiaozhe/article/details/7852824/
0 0
请问一下 有没有方法判断音量大小? 我想做一个,判断音量大小的来录音,避免无声音录制
哈哈 —— 2006年07月25日 @10:43 am
你好,看了你的哪个DX录音,然后自己动手试验了一下,程序运行不起来,有错误,不知道怎么改!
郑鹏辉 —— 2008年03月10日 @4:25 pm
运行没问题,只不过btnStop_Click后有线程没有结束,还没仔细看,不过还是来谢谢下。
seazon —— 2008年04月17日 @4:34 pm
private void WaitThread()
中while里写了ture,使这个循环一直出不来,mNotifyThread这个线程无法结束
seazon —— 2008年04月17日 @5:41 pm
博主,我使用你那个类,做了个应用程序,可以正常录音;
可我把MessageBox.Show换成throw new Exception后,然后改成window服务,可以录音,但没一点声音,咋回事呀??? (我是一个简单的window服务,服务是完全正常无错的)
net205 —— 2009年05月18日 @11:21 pm
这样做能实现B/S网页录音吗?
FlyBird —— 2009年07月22日 @10:47 am