运用Microsoft.DirectX.DirectSound和Microsoft.DirectX实现简单的录音功能

2023-10-31

1、首先要使用Microsoft.DirectX.DirectSound和Microsoft.DirectX这两个dll进行录音,需要先安装microsoft directx 9.0cz这个组件,

百度云盘下载地址:http://pan.baidu.com/s/1bpgbdP9,里面包含安装程序和两个dll

2、编写录音程序功能

1)编写录音支持的辅助类SoundRecord

源码:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO;
using Microsoft.DirectX;
using Microsoft.DirectX.DirectSound;

namespace SoundRecord
{
    public class SoundRecord
    {
        // 对DirectSound的支持
        int cNotifyNum = 16;       // 缓冲队列的数目
        int mNextCaptureOffset = 0;      // 该次录音缓冲区的起始点
        int mSampleCount = 0;            // 录制的样本数目
        int mNotifySize = 0;             // 每次通知大小
        int mBufferSize = 0;             // 缓冲队列大小
        string mFileName = string.Empty;     // 文件名
        FileStream mWaveFile = null;         // 文件流
        BinaryWriter mWriter = null;         // 写文件
        Capture mCapDev = null;              // 音频捕捉设备
        CaptureBuffer mRecBuffer = null;     // 缓冲区对象
        Notify mNotify = null;               // 消息通知对象
        WaveFormat mWavFormat;                       // 录音的格式
        Thread mNotifyThread = null;                 // 处理缓冲区消息的线程
        AutoResetEvent mNotificationEvent = null;    // 通知事件

        /// <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()
        {
            // 创建录音文件
            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>
        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;
            }
            // 设定通知的大小,默认为1s钟
            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.
        }
    }
}

2)调用方法的winform界面源码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Threading;
using System.IO;
using Microsoft.DirectX;
using Microsoft.DirectX.DirectSound;

namespace SoundRecord
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private SoundRecord recorder = new SoundRecord();

        private void btnStart_Click(object sender, EventArgs e)
        {
            string wavfile = null;
            wavfile = "test.wav";
            recorder.SetFileName(wavfile);
            recorder.RecStart();
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            recorder.RecStop();
            recorder = null;
        }   
    }
}

3)winform界面图

4)生成后的录音文件,在项目bin目录下

5)用播放器播放录音文件

附录:

录音的demo源码下载地址:http://pan.baidu.com/s/1hslW5Je

平时多记记,到用时才能看看,记录你的进步,分享你的成果




from: https://www.cnblogs.com/xielong/p/5710294.html


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

运用Microsoft.DirectX.DirectSound和Microsoft.DirectX实现简单的录音功能 的相关文章

  • Wwise指引贴

    几种音频软件的比较 Criware音频引擎跟Wwise在功能上有什么直接的区别么 为什么很多大厂都选择Wwise
  • 音频系统POP音的原理和解决方法

    音频系统POP音的原理和解决方法 目录 文章目录 音频系统POP音的原理和解决方法 目录 音频IC与功放IC的电源时序与功能模块使能时序 功放IC输入端INP与INN的阻抗匹配 增大VBIAS滤波电容 BTL输出和SE输出 减小输出端耦合电
  • 怎样使用Cubase进行人声消除

    所谓分离伴奏 指的就是消除人声 通常在一首歌曲的音频文件中 混音师一般都会将人声放在声像位置的正中间再输出为一个立体声音频文件 一般情况下是这样 但不代表全是这样 因此 人声的波形在该立体声音频文件的左声道和右声道中应该是相同或相似的 所以
  • 运用Microsoft.DirectX.DirectSound和Microsoft.DirectX实现简单的录音功能

    1 首先要使用Microsoft DirectX DirectSound和Microsoft DirectX这两个dll进行录音 需要先安装microsoft directx 9 0cz这个组件 百度云盘下载地址 http pan baid
  • WAV文件格式详解

    概述 Waveform Audio File Format WAVE 又或者是因为WAV后缀而被大众所知的 它采用RIFF Resource Interchange File Format 文件格式结构 通常用来保存PCM格式的原始音频数据
  • HTML5实现音频和视频嵌入

    简介 HTML5未出来之前 在线的音频和视频都是借助Flash或者第三方工具实现的 现在HTML5也支持了这方面的功能 在一个支持HTML5的浏览器中 不需要安装任何插件就能播放音频和视频 原生的支持音频和视频 为HTML5注入了巨大的发展
  • Android合并音频文件

    java view plain copy 需求 将两个amr格式音频文件合并为1个 注意 amr格式的头文件为6个字节的长度 param partsPaths 各部分路径 param unitedFilePath 合并后路径 public
  • AMR文件格式的解释

    一 什么是AMR AMR WB 全称Adaptive Multi Rate和Adaptive Multi Rate Wideband 主要用于移动设备的音频 压缩比比较大 但相对其他的压缩格式质量比较差 由于多用于人声 通话 效果还是很不错
  • Flutter音频播放之just_audio

    just audio的使用 just audio 它是一个用于播放音频的 Flutter 插件 安装和导入 just audio 要使用 just audio 库 需要将其添加到项目的 pubspec yaml 文件中 dependenci
  • DirectSound播放PCM(可播放实时采集的音频数据)

    前言 该篇整理的原始来源为http blog csdn net leixiaohua1020 article details 40540147 非常感谢该博主的无私奉献 写了不少关于不同多媒体库的博文 让我这个小白学习到不少 现在将其整理是
  • python:pydub模块

    一 安装 1 安装模块 pip install pydub 2 安装插件 云盘中下载文件ffmpeg 打开电脑上的控制面板 系统 高级系统设置 环境变量 然后双击path 看到如下的界面 然后点新建会出现一个新建的地址栏 你需要在这个新建地
  • C++ 播放音频流(PCM裸流)

    直接上代码 如果有需要可以直接建一个win32控制台程序然后将代码拷过去改个文件名就可以用了 注意将声道和频率与你自己的文件对应 当然我自己也用VS2008写了个例子上传了 如果有需要下载地址如下 点击打开链接 这份代码是打开文件截取一段数
  • DirectX编程:利用 DirectSound 录音

    DirectX编程 利用 DirectSound 录音 转载 http www cnblogs com stg609 archive 2008 10 24 1318931 html 花了一阵子 把DirectX安装后自带的帮助文件中的那部分
  • 免费的包噪音网站分享

    免费的包噪音网站分享 现代生活中 噪音扰人 影响健康和情绪 白噪音可以为人们提供放松心情 提高睡眠质量和专注力的帮助 现在有很多免费的白噪音网站可以任意使用和分享 包括海浪声 雨声 蝉鸣声等等 非常适合在办公室 家里或者旅途中使用 本文为您
  • Java把V3音频文件转化为wav文件的算法的代码

    将写内容过程经常用到的内容段做个备份 如下内容内容是关于Java把V3音频文件转化为wav文件的算法的内容 import java io BufferedInputStream import java io BufferedOutputSt
  • Using DirectSound to Play Audio Stream Data

    Download demo project 30 5 Kb Download source 3 27 Kb Introduction This article with its code shows how to play audio st
  • pulseaudio使用过程中遇到的问题

    W pulseaudio main c This program is not intended to be run as root unless system is specified E pulseaudio core util c H
  • 两路wav文件读取解析和混音输出并使用WaveOut相关API播放

    目录 wav文件格式简介 wav文件头定义 读取wav文件 读取背景音文件 音频混音 使用Windows WaveOut 相关API播放混音后的音频数据 将混音后的数据保存到新的wav文件中
  • FMOD Core API 指南

    目录 3 Core API 指南 3 1 什么是 Core API 3 2 链接的插件 3 2 1 静态 3 2 2 动态 3 3 API 功能
  • 免费音效素材网站,一次性介绍清楚

    不管是在游戏 电影 电视剧 短视频还是音频中 合适的音效能够更好的表达内容和渲染氛围 今天给大家分享几个免费音效素材 感兴趣的话可以接着往下看 一 制片帮素材 找音效 制片帮素材不仅有海量的优质视频素材 还有丰富的音效资源 分类清晰 更重要

随机推荐

  • Oracle ——删除表中重复记录

    为了方便 假设表名为Tbl 表中有三列col1 col2 col3 其中col1 col2是主键 并且 col1 col2上加了索引重复数据删除 1 通过创建临时表 把数据先导入到一个临时表中 然后删除原表的数据 再把数据导回原表 SQL语
  • 【PBR系列三】BRDF方程及渲染方程

    本文核心知识主要参照 现代计算机图形学入门 闫令琪课程课件PPT 后续光线追踪系列知识也源于此处 一 BRDF方程 通过上一部分所有辐射度量学各种概念的定义之后 我们可以从这样一个角度理解光线的反射 如下图所示 一个点 微分面积元 在接受到
  • 怎样安装NPM离线包

    因为一些 你懂的 原因 工作环境无法直接使用npm install联网安装npm包 稍微花了点时间研究了一下 Mark下来 有机会看源码再补充 最佳方案 别浪费时间了 最好还是在网络环境下把所需的包全部安装好 再想办法搬回来 尽管可以一个一
  • VMware Workstation 在此主机上不支持嵌套虚拟化。报错一秒解决

    VMware Workstation 在此主机上不支持嵌套虚拟化 这是由于VMware与Windows11自带的Hyper V冲突所导致的 简单的解决方法是 将虚拟机设置中的CPU虚拟化取消勾选 如图所示
  • Ubuntu 安装Google浏览器

    Ubuntu自带的浏览器是火狐浏览器 使用的时候多多少少有些不方便 这里安装Googel浏览器 下载 可以到 Ubuntu chrome去下载安装包 安装 首先到下载的根目录 cd Downloads sudo dpkg i google
  • Mybatis1.2 查询所有数据

    1 2 查询所有数据 1 2 1 编写接口方法 1 2 2 编写SQL语句 1 2 3 编写测试方法 1 2 4 起别名解决上述问题 1 2 5 使用resultMap解决上述问题 1 2 6 小结 如上图所示就页面上展示的数据 而这些数据
  • http 请求头大小写的问题

    如果是默认消息头名称 消息头格式已经固定 即便输入的大小写有误 也会给你翻译成默认的写法 如果自己定义的 会自动给你翻译成小写 所以传参数的名称都用小写字母即可 否则可能取不到值 比如encryptedString会取不到值 使用encry
  • 【华为OD机试真题】最短木板长度(python)100%通过率 超详细代码注释 代码解读

    华为OD机试真题 2022 2023 真题目录 点这里 华为OD机试真题 信号发射和接收 试读 点这里 华为OD机试真题 租车骑绿道 试读 点这里 最短木板长度 时间限制 1s空间限制 256MB限定语言 不限 题目描述 小明有 n 块木板
  • 在windows下C++使用Native wifi API获取SSID和连接信息

    在linux下获取当前连接的信息很是轻松的 但是在windows下相对比较复杂 虽然可以考虑使用cmd命令获取网卡的信息并分析出当前连接的SSID 但是对于网络环境比较复杂的情况下其实我们同样可以使用Native wifi API获取目前的
  • linphone-android for mac编译过程记录

    本文记录linphone andoroid在mac上的编译过程 在这里做下记录 希望对大家有所帮助 如有疑问发评论即可 环境搭建 代码下载 git clone git git linphone org linphone android gi
  • 阿里云学生服务器配置及免费学生机领取攻略

    阿里云学生服务器优惠活动从云翼计划升级为开发者成长计划 现在学生服务器活动为高校学生在家实践计划 学生用户群可以免费领取阿里云学生服务器 如果购买特价服务器只需要新用户即可 不需要学生认证即可享受优惠价 阿里云百科来详细说下阿里云学生服务器
  • 二、从C到C++(二) 引用、引用常见用途、指针和引用区别、const引用

    一 引用类型 引用 像一个自动能被编译器逆向引用的常量型指针 它通常用于函数的参数表中和函数的返回值 但也可以独立使用 比如 int x int r x 使用引用的一些规则 当引用被创建时 它必须被初始化 指针则可以在任何时候被初始化 一旦
  • 对主流编程语言的认识

    主流编程语言的认识 语言 用途 C 操作系统 嵌入式开发 C 游戏 图形图像 桌面软件 服务器 C 桌面软件 服务器 JAVA JAVA SE 桌面软件 Android JAVA EE 企业级应用 web开发 服务器 JAVA ME 手机应
  • el-upload上传视频获取视频宽高、时长信息(多文件、单文件)

  • frp安装

    安装包下载 Releases fatedier frp github com 一 服务端配置 上传安装包至可连外网服务器解压 tar xzfv frp 0 48 0 linux amd64 tar gz 进入解压文件夹修改frps ini文
  • Ajax是什么以及Ajax交互原理(详,图文并茂,原理篇)

    一 Ajax技术与原理 1 1 Ajax简介 Ajax Asynchronous JavaScript and XML 翻译成人话就是 异步的 javascript 和 XML 相结合的一种技术 需要澄清的是 Ajax不是新的编程语言 而是
  • 11、Restoring Vision in Adverse Weather Conditions with Patch-Based Denoising Diffusion Models

    简介 官网 https github com IGITUGraz WeatherDiffusion 在图像恢复中使用它们的一个主要障碍是它们的架构约束 禁止尺寸无关的图像恢复 而图像恢复基准和现实世界的问题由不同尺寸的图像组成 基于去噪扩散
  • 研一寒假C++复习笔记--深拷贝和浅拷贝代码实例

    目录 1 深拷贝和浅拷贝的基础概念 2 浅拷贝的代码实例 3 深拷贝代码实例 4 参考 1 深拷贝和浅拷贝的基础概念 浅拷贝 简单的赋值拷贝操作 深拷贝 在堆区重新申请空间 进行拷贝操作 2 浅拷贝的代码实例 include
  • idea2021.1运行时报:Cannot start compiler The output path is not specified for module StringTest 错误解决

    错因分析 根据提示可以知道 idea没有指定编译的输出路径 解决方法 直接点击提示下面的蓝色字体 Configure 如果Configure不能点击 可以通过 File gt Project Structure 打开 然后会弹出窗口
  • 运用Microsoft.DirectX.DirectSound和Microsoft.DirectX实现简单的录音功能

    1 首先要使用Microsoft DirectX DirectSound和Microsoft DirectX这两个dll进行录音 需要先安装microsoft directx 9 0cz这个组件 百度云盘下载地址 http pan baid