DirectX编程初级C# 中利用 DirectSound 录音Word文档下载推荐.docx
- 文档编号:17079996
- 上传时间:2022-11-28
- 格式:DOCX
- 页数:10
- 大小:62.39KB
DirectX编程初级C# 中利用 DirectSound 录音Word文档下载推荐.docx
《DirectX编程初级C# 中利用 DirectSound 录音Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《DirectX编程初级C# 中利用 DirectSound 录音Word文档下载推荐.docx(10页珍藏版)》请在冰豆网上搜索。
2.2可以同时播放多种声音。
2.3将高优先级的声音分配给由硬件控制的缓冲区。
2.4将普通的声音融入自定的3D环境中。
2.5可以给声音添加不同的效果,比如回声,合唱等。
2.6从麦克风或其它音频输入设备中捕获WAV声音。
3DirectSound有哪些主要对象?
对象
说明
作用
.Net中的类或结构体
设备对象
每个应用程序只有一个设备对象
用来管理设备,创建辅助缓冲区
Microsoft.DirectX.DirectSound.Capture
主缓冲区
一个应用程序只有一个主缓冲区
操控声音捕捉缓冲区和产生混音效果的区域
Microsoft.DirectX.DirectSound.CaptureBuffer
辅助缓冲区
每一个声音对应一个辅助缓冲区,可以有多个辅助缓冲区
用来存储要播放的声音文件,可建立多个辅助缓冲区来放多个要播放的声音文
Microsoft.DirectX.DirectSound.SecondaryBuffer
事件通知对象
一个缓冲区可以有多个通知对象
用于在缓冲区的特定点触发通知事件,来通知程序执行操作
Microsoft.DirectX.DirectSound.Notify
4其它辅助对象
音频格式
定义WAV音频格式,如采样频率、量化位数、声道数等
Microsoft.DirectX.DirectSound.WaveFormat
通知的事件
通知正在等待的线程已发生事件
System.Threading.AutoResetEvent
5必需知道的关键点
实在是太不厚道了!
!
辛苦写了半天,提交前没有事先复制一份,结果提交了半天给我展示了一个“无法显示该页面”,害得我又得从上次保存的地方开始写。
真晕呀!
还不知道能不能记起刚才写的。
都有点不想写了,可又觉得可惜。
可恶!
5.1WAVE格式
WAVE是录音时用的标准的WINDOWS文件格式,扩展名为“WAV”,
我们使用DirectSound采集的WAV声音,其音频数据是按照PCM(脉冲编码调制,对连续变化的模拟信号进行抽样、量化和编码产生的数据,0和1的组合)调制后放入缓冲区的。
WAVE文件格式采用RIFF文件格式结构,对PCM数据和其它一些音频信息进行相应的编排,从而最终形成的WAVE文件才能被音频播放器识别,才能进行播放。
5.2缓冲区指针
缓冲区是存放音频数据的地方,并且它还提供了我们两个指针:
读指针和捕捉指针。
它们的位置按照相对于缓冲区起始位置的偏移量计算。
读指针位于当前已经被完全捕捉到缓冲区的数据末尾。
捕捉指针位于当前将要从硬件中复制的数据块的末尾。
如果你想从缓冲区中读取数据,则只能从已经完全写入缓冲区的数据中读取,也就是说我们只能从偏移量小于读指针的地方读取。
5.3缓冲区通知
大家应该都知道时间相同的音频文件,WAVE文件会比其它格式的音频文件大得多,这是因为WAVE文件没有对数据进行压缩。
如果录音的时候,不限制缓冲区大小,那么你录制很短的时间可能就会占用很多内存,说不定不过多久,你的1G内存就不够用了。
因此我们必须对缓冲区的大小进行限制,而且当缓冲区满了之后,还可以重新从缓冲区起始处开始,用新的数据覆盖旧的数据。
那旧的数据怎么办呢?
如果你不想丢失旧的数据,那就得在旧的数据被覆盖之前,将它转移到其它地方。
如何才能在旧的数据没有被覆盖之前,将它转移走呢?
如果是你,你会采用什么办法?
有人提出通过轮询的办法,经常询问缓冲区是否满,满了则进行转移操作。
可是这样做会相当耗费性能。
微软提供了我们一个解决办法:
“通知”。
我们可以在缓冲区中的某些位置处设置通知,当读指针到达通知位置的时候,就会触发相应的事件执行转移操作。
是不是有点像操作系统中的“响应中断”呢?
6录音大致过程
6.1设置PCM格式(很多人喜欢说是设置WAVE格式,但是个人觉得这样说并不恰当,因为PCM才是用来描述数据采集的,而WAVE只是一种文件格式。
),设置相关的参数,如:
采样频率、量化位数等。
6.2创建WAVE文件,有没有搞错呀?
数据还没开始采集,怎么就先创建文件了呢?
我可以很明确得告诉你没有错。
因为RIFF结构的WAVE文件除了音频数据之外,还有其它数据,比如音频格式、格式长度等类似于文件头的数据。
有了文件头后,接下来就只需要把接收到的数据添加在这个后面就好了。
当然你一定要最后写的话,也不是不可以。
6.3建立设备对象,建立缓冲区对象。
6.4设置缓冲区通知,设置通知被触发后的事件。
6.5准备就绪后,就可以开始录音了。
6.6当通知被触发后,建立一个新的线程来处理数据转移的事件。
(建立一个新的线程,就是为了防止录音过程被中断)。
6.7录音结束,写入WAV文件尾。
这样一个可以播放的WAVE文件就OK了。
具体代码
不知道怎么形容现在的感觉了,真得很高兴大部分内容还记得。
不知道你现在是何心情,是否已经没什么热情看下去了?
本来想分两篇写的,但后来想想还是不浪费首面原创区的空间了。
如果你前面的已经看懂了,那下面对你来说可能只是写写代码的事了。
1.需要引用的命名空间和外部dll。
两个外部DLL为:
Microsoft.DirectX.dll和Microsoft.DirectX.DirectSound.dll
usingSystem.Threading;
usingSystem.IO;
usingMicrosoft.DirectX.DirectSound;
usingMicrosoft.DirectX;
2.用户变量
用户变量
privatestringstrRecSaveFile=string.Empty;
//文件保存路径
privateNotifymyNotify=null;
//缓冲区提示事件
privateFileStreamfsWav=null;
//保存的文件流
privateintiNotifyNum=16;
//通知的个数
privateintiBufferOffset=0;
//本次数据起始点,上一次数据的终点。
privateintiSampleSize=0;
//所采集到的数据大小
privateintiNotifySize=0;
//通知所在区域大小
privateintiBufferSize=0;
//缓冲区大小
privateBinaryWritermWriter;
privateCapturecapture=null;
//捕捉设备对象
privateCaptureBuffercapturebuffer=null;
//捕捉缓冲区
privateAutoResetEventnotifyevent=null;
privateThreadnotifythread=null;
privateWaveFormatmWavFormat;
//PCM格式
3.设置PCM格式
privateWaveFormatSetWaveFormat()
{
WaveFormatformat=newWaveFormat();
format.FormatTag=WaveFormatTag.Pcm;
//设置音频类型
format.SamplesPerSecond=22050;
//采样率(单位:
赫兹)典型值:
11025、22050、44100Hz
format.BitsPerSample=16;
//采样位数
format.Channels=1;
//声道
format.BlockAlign=(short)(format.Channels*(format.BitsPerSample/8));
//单位采样点的字节数
format.AverageBytesPerSecond=format.BlockAlign*format.SamplesPerSecond;
returnformat;
//按照以上采样规格,可知采样1秒钟的字节数为22050*2=55100B约为53K
}
4.创建WAVE文件
创建WAVE文件
privatevoidCreateWaveFile(stringstrFileName)
fsWav=newFileStream(strFileName,FileMode.CreateNew);
mWriter=newBinaryWriter(fsWav);
/**************************************************************************
Hereiswherethefilewillbecreated.A
wavefileisaRIFFfile,whichhaschunks
ofdatathatdescribewhatthefilecontains.
AwaveRIFFfileisputtogetherlikethis:
The12byteRIFFchunkisconstructedlikethis:
Bytes0-3:
'
R'
I'
F'
Bytes4-7:
Lengthoffile,minusthefirst8bytesoftheRIFFdescription.
(4bytesfor"
WAVE"
+24bytesforformatchunklength+
8bytesfordatachunkdescription+actualsampledatasize.)
Bytes8-11:
W'
A'
V'
E'
The24byteFORMATchunkisconstructedlikethis:
f'
m'
t'
Theformatchunklength.Thisisalways16.
Bytes8-9:
Filepadding.Always1.
Bytes10-11:
Numberofchannels.Either1formono,or2forstereo.
Bytes12-15:
Samplerate.
Bytes16-19:
Numberofbytespersecond.
Bytes20-21:
Bytespersample.1for8bitmono,2for8bitstereoor
16bitmono,4for16bitstereo.
Bytes22-23:
Numberofbitspersample.
TheDATAchunkisconstructedlikethis:
d'
a'
Lengthofdata,inbytes.
Bytes8-
:
Actualsampledata.
***************************************************************************/
char[]ChunkRiff={'
'
};
char[]ChunkType={'
char[]ChunkFmt={'
char[]ChunkData={'
shortshPad=1;
//File
intnFormatChunkLength=0x10;
//Formatchunklength.
intnLength=0;
//Filelength,minusfirst8bytesofRIFFdescription.Thiswillbefilledinlater.
shortshBytesPerSample=0;
//Bytespersample.
//一个样本点的字节数目
if(8==mWavFormat.BitsPerSample&
&
1==mWavFormat.Channels)
shBytesPerSample=1;
elseif((8==mWavFormat.BitsPerSample&
2==mWavFormat.Channels)||(16==mWavFormat.BitsPerSample&
1==mWavFormat.Channels))
shBytesPerSample=2;
elseif(16==mWavFormat.BitsPerSample&
2==mWavFormat.Channels)
shBytesPerSample=4;
//RIFF块
mWriter.Write(ChunkRiff);
mWriter.Write(nLength);
mWriter.Write(ChunkType);
//WAVE块
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);
//Thesamplelengthwillbewritteninlater.
5.建立两个对象
建立设备对象和缓冲区对象
privateboolCreateCaputerDevice()
//首先要玫举可用的捕捉设备
CaptureDevicesCollectioncapturedev=newCaptureDevicesCollection();
Guiddevguid;
if(capturedev.Count>
0)
devguid=capturedev[0].DriverGuid;
else
MessageBox.Show("
当前没有可用于音频捕捉的设备"
"
系统提示"
);
returnfalse;
//利用设备GUID来建立一个捕捉设备对象
capture=newCapture(devguid);
returntrue;
privatevoidCreateCaptureBuffer()
{//想要创建一个捕捉缓冲区必须要两个参数:
缓冲区信息(描述这个缓冲区中的格式等),缓冲设备。
CaptureBufferDescriptionbufferdescription=newCaptureBufferDescription();
bufferdescription.Format=mWavFormat;
//设置缓冲区要捕捉的数据格式
iNotifySize=1024;
//设置通知大小
iBufferSize=iNotifyNum*iNotifySize;
bufferdescription.BufferBytes=iBufferSize;
capturebuffer=newCaptureBuffer(bufferdescription,capture);
//建立设备缓冲区对象
6.设置通知以及相应的事件
设置通知及其相应的事件
//设置通知
privatevoidCreateNotification()
BufferPositionNotify[]bpn=newBufferPositionNotify[iNotifyNum];
//设置缓冲区通知个数
//设置通知事件
notifyevent=newAutoResetEvent(false);
notifythread=newThread(RecoData);
notifythread.Start();
for(inti=0;
i<
iNotifyNum;
i++)
bpn[i].Offset=iNotifySize+i*iNotifySize-1;
//设置具体每个的位置
bpn[i].EventNotifyHandle=notifyevent.Handle;
myNotify=newNotify(capturebuffer);
myNotify.SetNotificationPositions(bpn);
//线程中的事件
privatevoidRecoData()
while(true)
//等待缓冲区的通知消息
notifyevent.WaitOne(Timeout.Infinite,true);
//录制数据
RecordCapturedData();
//真正转移数据的事件,其实就是把数据转移到WAV文件中。
privatevoidRecordCapturedData()
byte[]capturedata=null;
intreadpos=0,capturepos=0,locksize=0;
capturebuffer.GetCurrentPosition(outcapturepos,outreadpos);
locksize=readpos-iBufferOffset;
//这个大小就是我们可以安全读取的大小
if(locksize==0)
return;
if(locksize<
{//因为我们是循环的使用缓冲区,所以有一种情况下为负:
当文以载读指针回到第一个通知点,而Ibuffeoffset还在最后一个通知处
locksize+=iBufferSize;
capturedata=(byte[])capturebuffer.Read(iBufferOffset,typeof(byte),LockFlag.FromWriteCursor,locksize);
mWriter.Write(capturedata,0,capturedata.Length);
//写入到文件
iSampleSize+=capturedata.Length;
iBufferOffset+=capturedata.Length;
iBufferOffset%=iBufferSize;
//取模是因为缓冲区是循环的。
7.
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- DirectX编程初级C# 中利用 DirectSound 录音 DirectX 编程 初级 C# 利用
![提示](https://static.bdocx.com/images/bang_tan.gif)