微型计算机接口技术大作业

更新时间: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;

}

}

结果展示

本文来源:https://www.bwwdw.com/article/rmo1.html

Top