您好,欢迎访问三七文档
C#中使用DirectSound录音一.声卡录音的基本原理为了实现一个录音的基本过程,至少需要以下对象的支持:1.录音设备,对我们的PC设备就是声卡。这个录音设备可以进行的操作应该有开始和关闭。2.缓冲区,也就是录制的声音放在哪里的问题。二.DirectSound对录音的描述模型1.DirectSound对录音的支持类ØCapture,设备对象,可以看作是声卡的描述。ØCaptureBuffer,缓冲区对象,存放录入的音频数据。ØNotify,事件通知对象,由于录音是一个长时间的过程,因此使用一个缓冲队列(多个缓冲区)接收数据,每当一个缓冲区满的时候,系统使用这个对象通知应用程序取走这个缓冲区,并继续录音。以上三个对象是进行录音操作的主要对象,由于在C++中对DirectSound的操作DirectX帮助文档中已经有很详细的说明,这里就不再赘述了。本文是针对ManagedCode。除了以上三个主要的DirectSound类,还需要以下几个辅助类。ØWaveFormat,描述了进行录制的声音波形的格式,例如采样率,单声道还是立体声,每个采样点的长度等等。ØThread,线程类,由于录音的过程是需要不断处理缓冲区满的事件,因此新建一个线程对此进行单独处理。ØAutoResetEvent,通知的事件,当缓冲区满的时候,使用该事件作为通知事件。三.代码解析(SoundRecord类)1.需要引用的程序集usingSystem;usingSystem.Windows.Forms;usingSystem.Threading;usingSystem.IO;//对DirectSound的支持usingMicrosoft.DirectX;usingMicrosoft.DirectX.DirectSound;2.SoundRecord的成员数据publicconstintcNotifyNum=16;//缓冲队列的数目privateintmNextCaptureOffset=0;//该次录音缓冲区的起始点privateintmSampleCount=0;//录制的样本数目privateintmNotifySize=0;//每次通知大小privateintmBufferSize=0;//缓冲队列大小privatestringmFileName=string.Empty;//文件名privateFileStreammWaveFile=null;//文件流privateBinaryWritermWriter=null;//写文件privateCapturemCapDev=null;//音频捕捉设备privateCaptureBuffermRecBuffer=null;//缓冲区对象privateNotifymNotify=null;//消息通知对象privateWaveFormatmWavFormat;//录音的格式privateThreadmNotifyThread=null;//处理缓冲区消息的线程privateAutoResetEventmNotificationEvent=null;//通知事件3.对外操作的函数///summary///构造函数,设定录音设备,设定录音格式.////summarypublicSoundRecord(){//初始化音频捕捉设备InitCaptureDevice();//设定录音格式mWavFormat=CreateWaveFormat();}///summary///设定录音结束后保存的文件,包括路径////summary///paramname=filename保存wav文件的路径名/parampublicvoidSetFileName(stringfilename){mFileName=filename;}///summary///开始录音////summarypublicvoidRecStart(){//创建录音文件CreateSoundFile();//创建一个录音缓冲区,并开始录音CreateCaptureBuffer();//建立通知消息,当缓冲区满的时候处理方法InitNotifications();mRecBuffer.Start(true);}///summary///停止录音////summarypublicvoidRecStop(){//关闭通知消息if(null!=mNotificationEvent)mNotificationEvent.Set();//停止录音mRecBuffer.Stop();//写入缓冲区最后的数据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;}4.内部调用函数///summary///初始化录音设备,此处使用主录音设备.////summary///returns调用成功返回true,否则返回false/returnsprivateboolInitCaptureDevice(){//获取默认音频捕捉设备CaptureDevicesCollectiondevices=newCaptureDevicesCollection();//枚举音频捕捉设备GuiddeviceGuid=Guid.Empty;//音频捕捉设备的IDif(devices.Count0)deviceGuid=devices[0].DriverGuid;else{MessageBox.Show(系统中没有音频捕捉设备);returnfalse;}//用指定的捕捉设备创建Capture对象try{mCapDev=newCapture(deviceGuid);}catch(DirectXExceptione){MessageBox.Show(e.ToString());returnfalse;}returntrue;}///summary///创建录音格式,此处使用16bit,16KHz,Mono的录音格式////summary///returnsWaveFormat结构体/returnsprivateWaveFormatCreateWaveFormat(){WaveFormatformat=newWaveFormat();format.FormatTag=WaveFormatTag.Pcm;//PCMformat.SamplesPerSecond=16000;//16KHzformat.BitsPerSample=16;//16Bitformat.Channels=1;//Monoformat.BlockAlign=(short)(format.Channels*(format.BitsPerSample/8));format.AverageBytesPerSecond=format.BlockAlign*format.SamplesPerSecond;returnformat;}///summary///创建录音使用的缓冲区////summaryprivatevoidCreateCaptureBuffer(){//缓冲区的描述对象CaptureBufferDescriptionbufferdescription=newCaptureBufferDescription();if(null!=mNotify){mNotify.Dispose();mNotify=null;}if(null!=mRecBuffer){mRecBuffer.Dispose();mRecBuffer=null;}//设定通知的大小,默认为1s钟mNotifySize=(1024mWavFormat.AverageBytesPerSecond/8)?1024:(mWavFormat.AverageBytesPerSecond/8);mNotifySize-=mNotifySize%mWavFormat.BlockAlign;//设定缓冲区大小mBufferSize=mNotifySize*cNotifyNum;//创建缓冲区描述bufferdescription.BufferBytes=mBufferSize;bufferdescription.Format=mWavFormat;//录音格式//创建缓冲区mRecBuffer=newCaptureBuffer(bufferdescription,mCapDev);mNextCaptureOffset=0;}///summary///初始化通知事件,将原缓冲区分成16个缓冲队列,在每个缓冲队列的结束点设定通知点.////summary///returns是否成功/returnsprivateboolInitNotifications(){if(null==mRecBuffer){MessageBox.Show(未创建录音缓冲区);returnfalse;}//创建一个通知事件,当缓冲队列满了就激发该事件.mNotificationEvent=newAutoResetEvent(false);//创建一个线程管理缓冲区事件if(null==mNotifyThread){mNotifyThread=newThread(newThreadStart(WaitThread));mNotifyThread.Start();}//设定通知的位置BufferPositionNotify[]PositionNotify=newBufferPositionNotify[cNotifyNum+1];for(inti=0;icNotifyNum;i++){PositionNotify[i].Offset=(mNotifySize*i)+mNotifySize-1;PositionNotify[i].EventNotifyHandle=mNotificationEvent.Handle;}mNotify=newNotify(mRecBuffer);mNotify.SetNotificationPositions(PositionNotify,cNotifyNum);returntrue;}///summary///将录制的数据写入wav文件////summaryprivatevoidRecordCapturedData(){byte[]CaptureData=null;intReadPos;intCapturePos;intLockSize;mRecBuffer.GetCurrentPosition(outCapturePos,outReadPos);LockSize=ReadPos-mNextCaptureOffset;if(LockSize0)LockSize+=mBufferSize;//对齐缓冲区边界,实际上由于开始设定完整,这个操作是多余的.LockSize-=(LockSize%mNotifySize);if(0==LockSize)return;//读取缓冲区内的数据CaptureData=(byte[])mRecBuffer.Read(mNextCaptureOffset,typeof(byte),LockFlag.None,LockSize);//写入Wav文件mWriter.Write(CaptureData,0,CaptureData.Length);//更新已经录制的数据长度.mSampleCount+=CaptureData.Leng
本文标题:C#实现录音
链接地址:https://www.777doc.com/doc-4292709 .html