微型计算机接口技术大作业
更新时间:2023-06-11 08:37:01 阅读量: 实用文档 文档下载
微型计算机接口技术
微型计算机接口大作业
——DirectX录音程序的实现
学院: 软件学院
专业: 网络安全
姓名:
学号:
2011年6月11日星期六
微型计算机接口技术
程序简介
该程序使用DirectX提供的DirectSound来,控制音频驱动程序的各种接口,来录制和储存WAV音频文件。
使用接口举例
DirectSound中Capture捕获器对象来获取音频捕捉设备
DirectSound中的CaptureBuffer捕获缓存储存由音频捕获设备捕获的数据。 DirectSound中Notify消息通知对象对象来对缓冲区进行记录和界限 。
DirectSound中的WaveFormat设定录音的格式。
WAV文件的二进制形式
WAV文件头格式:
虚拟地址 数据长度 类型 描述
00H 4 char "RIFF"标志
04H 4 long int 文件长度
08H 4 char "WAVE"标志
0CH 4 char "fmt"标志
10H 4 过渡字节(不定)
14H 2 int 格式类别(10H为PCM形式的声音数据) 16H 2 int 通道数,单声道为1,双声道为2
18H 2 int 采样率(每秒样本数),表示每个通道的播放速度,
1CH 4 long int 波形音频数据传送速率,其值为通道数×每秒数据位数×每样 本的数据位数/8。播放软件利用此值可以估计缓冲区的大小。 20H 2 int 数据块的调整数(按字节算的),其值为通道数×每样本的数据位值/8。播放软件需要一次处理多个该值大小的字节数据,以便将其值用于缓冲区的调整。
22H 2 每样本的数据位数,表示每个声道中各个样本的数据位数。如果有多个声道,对每个声道而言,样本大小都一样。
24H 4 char 数据标记符"data"
28H 4 long int 语音数据的长度
缓冲区指针
缓冲区是存放音频数据的地方,并且它还提供了我们两个指针:读指针和捕捉指针。它们的位置按照相对于缓冲区起始位置的偏移量计算。读指针位于当前已经被完全捕捉到缓冲区的数据末尾。捕捉指针位于当前将要从硬件中复制的数据块的末尾。如果你想从缓冲区中读取数据,则只能从已经完全写入缓冲区的数据中读取,也就是说我们只能
微型计算机接口技术
从偏移量小于读指针的地方读取。
缓冲区通知 时间相同的音频文件,WAVE文件会比其它格式的音频文件大得多,这是因为WAVE
文件没有对数据进行压缩。如果录音的时候,不限制缓冲区大小,那么你录制很短的时间可能就会占用很多内存,说不定不过多久,你的2G内存就不够用了。因此我们必须对缓冲区的大小进行限制,而且当缓冲区满了之后,还可以重新从缓冲区起始处开始,用新的数据覆盖旧的数据。
为保证不丢失旧的数据,那就得在旧的数据被覆盖之前,将它转移到其它地方。微软提供了“通知”的方法。在缓冲区中的某些位置处设置通知,当读指针到达通知位置的时候,就会触发相应的事件执行转移操作。
捕获流程
微型计算机接口技术
程序代码
上述主要在RecordSound类中
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO;
// 对DirectSound的支持
using Microsoft.DirectX;
using Microsoft.DirectX.DirectSound;
namespace _001
{
class SoundRecord
{
public const int cNotifyNum = 16; // 缓冲队列的数目
private int mNextCaptureOffset = 0; // 该次录音缓冲区的起始点 private int mSampleCount = 0; // 录制的样本数目 private int mNotifySize = 0; // 每次通知大小? private int mBufferSize = 0; // 缓冲队列大小
private string mFileName = string.Empty; // 文件名?
private FileStream mWaveFile = null; // 文件流
private BinaryWriter mWriter = null; // 写文件
private Capture mCapDev = null; // 音频捕捉设备 private CaptureBuffer mRecBuffer = null; // 缓冲区对象 private Notify mNotify = null; // 消息通知对象
private WaveFormat mWavFormat; // 录音的格式 private Thread mNotifyThread = null; // 处理缓冲区消息的线程
private AutoResetEvent mNotificationEvent = null; // 通知事件t
/// <summary>
/// 构造函数,设定录音设备,设定录音格式.
/// </summary>
public SoundRecord()
{
// 初始化音频捕捉设备
InitCaptureDevice();
// 设定录音格式
mWavFormat = CreateWaveFormat();
}
微型计算机接口技术
/// <summary>
/// 设定录音结束后保存的文件,包括路径
/// </summary>
/// <param name="filename">保存wav文件的路径名</param>
public void SetFileName(string filename)
{
mFileName = filename;
}
/// <summary>
/// 开始录音
/// </summary>
public void RecStart()
{
// 创建录音文件t
CreateSoundFile();
// 创建一个录音缓冲区并开始录音
CreateCaptureBuffer();
// 建立通知消息,当Ì缓冲区满的时候处理方法
InitNotifications();
mRecBuffer.Start(true);
}
/// <summary>
/// 停止录音
/// </summary>
public void RecStop()
{
// 关闭通知消息
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;
}
微型计算机接口技术
/// <summary>
/// 初始化录音设备,此处使用主录音设备
/// </summary>
/// <returns>调用成功返回true,否则返回false</returns>
private bool InitCaptureDevice()
{
// 获取默认音频捕捉设备
CaptureDevicesCollection devices = new CaptureDevicesCollection(); // 枚举音频捕捉设备
Guid deviceGuid = Guid.Empty; // 音频捕捉设备的ID
if (devices.Count>0)
deviceGuid = devices[0].DriverGuid;
else
{
MessageBox.Show("系统中没有音频捕捉设备");
return false;
}
// 用指定的捕捉设备创建Capture对象
try
{
mCapDev = new Capture(deviceGuid);
}
catch (DirectXException e)
{
MessageBox.Show(e.ToString());
return false;
}
return true;
}
/// <summary>
/// 创建录音格式,此处使用16bit,16KHz,Mono的录音格式
/// </summary>
/// <returns>WaveFormat结构体</returns>
private WaveFormat CreateWaveFormat()
{
WaveFormat format = new WaveFormat();
format.FormatTag = WaveFormatTag.Pcm; // PCM
format.SamplesPerSecond = 16000; // 16KHz
format.BitsPerSample = 16; // 16Bit
format.Channels = 1; // Mono
微型计算机接口技术
format.BlockAlign = (short)(format.Channels *
(format.BitsPerSample / 8));
format.AverageBytesPerSecond = format.BlockAlign *
format.SamplesPerSecond;
return format;
}
/// <summary>
/// 创建录音使用的缓冲区
/// </summary>
private void CreateCaptureBuffer()
{
// 缓冲区的描述对象
CaptureBufferDescription bufferdescription = new
CaptureBufferDescription();
if (null != mNotify)
{
mNotify.Dispose();
mNotify = null;
}
if (null != mRecBuffer)
{
mRecBuffer.Dispose();
mRecBuffer = null;
}
// 设定通知的大小,默认为s
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;
}
/// <summary>
/// 初始化通知事件,将原缓冲区分成16个缓冲队列,在每个缓冲队列的结束点设定通知点
/// </summary>
/// <returns>是否成功</returns>
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.Handle;
}
mNotify = new Notify(mRecBuffer);
mNotify.SetNotificationPositions(PositionNotify, cNotifyNum); return true;
}
/// <summary>
/// 将录制的数据写入wav文件
/// </summary>
private void RecordCapturedData()
{
byte[] CaptureData = null;
int ReadPos;
int CapturePos;
int LockSize;
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);
// 写入Wav文件
mWriter.Write(CaptureData, 0, CaptureData.Length);
// 更新已经录制的数据长度
mSampleCount += CaptureData.Length;
// 移动录制数据的起始点,通知消息只负责指示产生消息的位置,并不记录上次录制的位置
mNextCaptureOffset += CaptureData.Length;
mNextCaptureOffset %= mBufferSize; // Circular buffer
}
/// <summary>
/// 接收缓冲区满消息的处理线程
/// </summary>
private void WaitThread()
{
while(true)
{
// 等待缓冲区的通知消息
mNotificationEvent.WaitOne(Timeout.Infinite, true); // 录制数据
RecordCapturedData();
}
}
/// <summary>
/// 创建保存的波形文件,并写入必要的文件头
/// </summary>
private void CreateSoundFile()
{
// Open up the wave file for writing.
mWaveFile = new FileStream(mFileName, FileMode.Create); mWriter = new BinaryWriter(mWaveFile);
// Set up file with RIFF chunk info.
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; // File padding
int nFormatChunkLength = 0x10; // Format chunk length.
int nLength = 0; // File length, minus first 8 bytes of RIFF description. This will be filled in later.
微型计算机接口技术
short shBytesPerSample = 0; // Bytes per sample.
// 一个样本点的字节数目
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;
// 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); // The sample length will be written in later.
}
}
}
主界面窗口代码
public partial class Form1 : Form
{
private SoundRecord sd = null;
public Form1()
{
InitializeComponent();
sd = new SoundRecord();
}
private void button1_Click(object sender, EventArgs e)
{
string wavfile = null;
wavfile = "test.wav";
微型计算机接口技术
sd.SetFileName(wavfile);
sd.RecStart();
}
private void button2_Click(object sender, EventArgs e) {
sd.RecStop();
sd = null;
}
}
结果展示
正在阅读:
微型计算机接口技术大作业06-11
事业单位岗位设置实施方案04-19
房地产基本知识04-04
2016-2022年中国砗磲市场深度调研与行业前景预测报告04-26
铁路工程抗震设计规范06-29
源自日常生活的中考物理试题05-12
朗文交互英语第二册MB34508-09
- 教学能力大赛决赛获奖-教学实施报告-(完整图文版)
- 互联网+数据中心行业分析报告
- 2017上海杨浦区高三一模数学试题及答案
- 招商部差旅接待管理制度(4-25)
- 学生游玩安全注意事项
- 学生信息管理系统(文档模板供参考)
- 叉车门架有限元分析及系统设计
- 2014帮助残疾人志愿者服务情况记录
- 叶绿体中色素的提取和分离实验
- 中国食物成分表2020年最新权威完整改进版
- 推动国土资源领域生态文明建设
- 给水管道冲洗和消毒记录
- 计算机软件专业自我评价
- 高中数学必修1-5知识点归纳
- 2018-2022年中国第五代移动通信技术(5G)产业深度分析及发展前景研究报告发展趋势(目录)
- 生产车间巡查制度
- 2018版中国光热发电行业深度研究报告目录
- (通用)2019年中考数学总复习 第一章 第四节 数的开方与二次根式课件
- 2017_2018学年高中语文第二单元第4课说数课件粤教版
- 上市新药Lumateperone(卢美哌隆)合成检索总结报告
- 微型计算机
- 接口
- 作业
- 技术
- 情态动词的用法 (推测),专四写作,不定式和动名词
- 40个CSS与JS风格和功能技术处理
- 让美术教学插上想象的翅膀(黄剑文)
- XX种植养殖农民专业合作社简介
- 聚合氯化铝的投放比例
- 土地登记实务(地籍地政类)
- 2014广西教师招聘考试《教育学与教学法基础知识》总结
- 欧阳询楷书结体三十六法 译文
- 王海明论公正的一般问题
- 再生制动中牵引_制动能量与燃油消耗的研究_项党
- 让爱伴随孩子成长
- 高低压成套开关柜培训教材1
- 注册会计师讲义《财管》第九章资本预算03
- A_O_化学除磷工艺中DMBR动态膜成膜条件研究
- 2011年全国各地中考生物试题考点分类汇编考点30 血液循环和输血
- 华北电网自动发电控制综述_刘永奇
- (完整word版)英语名词单复数练习题带答案
- 查经资料-以诺二书
- 日本开发木材干燥/REO防腐处理装置
- 修饰表格教学案例