C#基于DirectX的录音示例

一.介绍

此程序是在我项目中很小的一个功能。需要通过软件控制,录制音频,再存储为WAV文件。因为项目对采样率要求不高,不也需要进行变化,所以在程序里,我将采样率、位数、通道数都是设为一个固定的值。如果需要修改这几个参数,可作为参数代入。

二.程序

1.初始化录音设备

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;
        }

创建录音wav文件头,这里我设的固定值

private WaveFormat CreateWaveFormat()
    {
        WaveFormat format = new WaveFormat();
        format.FormatTag = WaveFormatTag.Pcm;   // PCM
        format.SamplesPerSecond = 12000;        // 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;
    }

3.创建录音使用的缓冲区

private void CreateCaptureBuffer()
        {
            // 缓冲区的描述对象
            CaptureBufferDescription bufferdescription = new CaptureBufferDescription();
            if (null != mNotify)
            {
                mNotify.Dispose();
                mNotify = null;
            }
            if (null != mRecBuffer)
            {
                mRecBuffer.Dispose();
                mRecBuffer = null;
            }
            // 设定通知的大小,默认为1s钟
            mNotifySize = (1024 > mWavFormat.AverageBytesPerSecond / 8) ? 1024 : (mWavFormat.AverageBytesPerSecond / 8);
            mNotifySize -= mNotifySize % mWavFormat.BlockAlign;
            mNotifySize = 1200;
            // 设定缓冲区大小
            mBufferSize = mNotifySize * cNotifyNum;

            // 创建缓冲区描述           
            bufferdescription.BufferBytes = mBufferSize;
            bufferdescription.Format = mWavFormat;           // 录音格式

            // 创建缓冲区
            mRecBuffer = new CaptureBuffer(bufferdescription, mCapDev);
            mNextCaptureOffset = 0;
        }

4.初始化通知事件

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;
        }

5.开始录音

public void RecStart()
        {
            // 创建录音文件
            CreateSoundFile();
            // 创建一个录音缓冲区,并开始录音
            CreateCaptureBuffer();
            // 建立通知消息,当缓冲区满的时候处理方法
            InitNotifications();
            mRecBuffer.Start(true);
        }

6.将录制的数据写入wav文件

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);
            if (isNowSound)
            {
                // 读取缓冲区内的数据
                byte[] dataBody = new byte[1202];
                dataBody[0] = 0x66;
                dataBody[1] = 0x01;
                Array.Copy(CaptureData, 0, dataBody, 2, 1200);
                byte[] dataSend = GlobalClass.GetSendData(0x03, 0x83, 0xAB, dataBody);
                m_Attack.udp_Attack.UdpSend(m_Attack.c_RemoteIP, m_Attack.c_RemotePort, dataSend);
            }
            // 写入Wav文件
            mWriter.Write(CaptureData, 0, CaptureData.Length);
            // 更新已经录制的数据长度
            mSampleCount += CaptureData.Length;
            // 移动录制数据的起始点,通知消息只负责指示产生消息的位置,并不记录上次录制的位置
            mNextCaptureOffset += CaptureData.Length;
            mNextCaptureOffset %= mBufferSize; // Circular buffer
        }

7.结束录音

public void RecStop()
        {
            // 关闭通知消息
            if (null != mNotificationEvent)
                mNotificationEvent.Set();
            // 停止录音
            mRecBuffer.Stop();

            // 写入缓冲区最后的数据
            RecordCapturedData();
            Thread.Sleep(200);
            // 回写长度信息
            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;

        }

按照上述流程,基本就完成了音频的录音。
在这里插入图片描述

这个完整的录音音频的类和调用示例在这里下载

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

muyiliu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值