第6课 用window API捕获麦克风数据并加入队列备用

news/2025/4/1 2:45:48/

今天是2024年1月1日,新年的第一缕阳光已经普照大地,祝愿看到这篇文章的所有程序员或程序爱好者都能在新的一年里持之以恒,事业有成。

今天也是我加入CSDN的第4100天,但回过头看一看,这么长的时间也没有在CSDN写下几篇文章,真是一种遗憾。为了弥补这个遗憾,我会继续坚持把这套教程写完。目前的教程总体而言写的还比较粗略,很多细节没有展开写,后面找时间再继续优化,现在主要是梳理一下整体思路,先搞个框架出来。

1.捕获麦克风数据入队列备用

上节课我们已经用openCV成功打开摄像头并实现了预览功能,这节课我们来看一下如何捕获麦克风数据。要捕获麦克风数据,就要先打开麦克风,打开麦克风的方法与《第3课 使用FFmpeg获取并播放音频流》中打开扬声器的方法差不多:

//打开麦克风
void fmle::openMic(){int nIndex = 0;inWaveform.wFormatTag = WAVE_FORMAT_PCM;inWaveform.nSamplesPerSec = 44100;inWaveform.wBitsPerSample = 16;inWaveform.nChannels = 2;inWaveform.nBlockAlign = (inWaveform.wBitsPerSample * inWaveform.nChannels) / 8;inWaveform.nAvgBytesPerSec = inWaveform.nBlockAlign * inWaveform.nSamplesPerSec;inWaveform.cbSize = 0;waveInOpen(&hWaveIn, nIndex, &inWaveform, (DWORD)micCallback, 0L, CALLBACK_FUNCTION);waveHdrArr = new WAVEHDR[audioDataArrNum];for (int i = 0; i < audioDataArrNum; i++){waveHdrArr[i].lpData = new char[audioDataSize];waveHdrArr[i].dwBufferLength = audioDataSize;waveHdrArr[i].dwBytesRecorded = 0;waveHdrArr[i].dwUser = NULL;waveHdrArr[i].dwFlags = 0;waveHdrArr[i].dwLoops = 1;waveHdrArr[i].lpNext = NULL;waveHdrArr[i].reserved = 0;waveInPrepareHeader(hWaveIn, &waveHdrArr[i], sizeof(WAVEHDR));waveInAddBuffer(hWaveIn, &waveHdrArr[i], sizeof(WAVEHDR));}waveInStart(hWaveIn);
}DWORD CALLBACK fmle::micCallback(HWAVEIN hwavein, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{switch (uMsg){case WIM_OPEN:TRACE("WIM_OPEN\n");break;case WIM_DATA:{//TRACE("WIM_DATA\n");LPWAVEHDR pwh = (LPWAVEHDR)dwParam1;if (pwh->dwBytesRecorded > 0){EnterCriticalSection(&pThis->queLock);pThis->tmpAudioQueObj.type = 0;pThis->tmpAudioQueObj.dataArr = pwh->lpData;pThis->tmpAudioQueObj.dataLen = pwh->dwBytesRecorded;pThis->inAudioQue.push(pThis->tmpAudioQueObj);if (pThis->inAudioQue.size() > pThis->audioDataArrNum){pThis->inAudioQue.front().dataLen = 0;pThis->inAudioQue.front().dataArr = NULL;pThis->inAudioQue.front().dataLen = NULL;delete[]pThis->inAudioQue.front().dataArr;pThis->inAudioQue.pop();}LeaveCriticalSection(&pThis->queLock);}waveInAddBuffer(pThis->hWaveIn, pwh, sizeof(WAVEHDR));TRACE("pThis->inAudioQue.size():%d\n", pThis->inAudioQue.size());}break;case WIM_CLOSE:TRACE("WIM_CLOSE\n");waveInStop(pThis->hWaveIn);waveInReset(pThis->hWaveIn);waveInClose(pThis->hWaveIn);break;default:break;}return 0;
}

2.将麦克风数据存成文件检测是否正常

上述方法虽然可以将麦克风数据存入队列备用,但我们如何知道它是否正确捕获了呢?我们可以把捕获的pcm数据先存入文件:

FILE *pcmFile;
fopen_s(&pcmFile, "rec.pcm", "wb");
fwrite(pwh->lpData, 1, pwh->dwBytesRecorded, pcmFile);

想一想,上述代码应该分别加在什么地方呢?

录制pcm文件后可以使用Audacity来导入pcm文件测试录制数据是否正确。


http://www.ppmy.cn/news/1288653.html

相关文章

【C++】STL 容器 - map 关联容器 ③ ( map 容器常用 api 操作 | map 容器迭代器遍历 | map#insert 函数返回值处理 )

文章目录 一、map 容器迭代器遍历1、map 容器迭代器2、代码示例 二、map 容器插入结果处理1、map#insert 函数返回值处理2、代码示例 一、map 容器迭代器遍历 1、map 容器迭代器 C 语言中 标准模板库 ( STL ) 的 std::map 容器 提供了 begin() 成员函数 和 end() 成员函数 , 这…

ORACLE Primavera Unifier v23.12 最新虚拟机(VM)分享下载

引言 根据上周的计划&#xff0c;我近日简单制作了一个基于ORACLE Primavera Unifier 最新版23.12的虚拟机演示环境&#xff0c;里面包括了unifier的全套系统服务 此虚拟系统环境仅用于演示、培训和测试目的。如要在生产环境中使用此虚拟机&#xff0c;请您与Oracle 销售代表联…

大数据背后的绿色收割:基于Hadoop的农产品价格信息智能分析

大数据背后的绿色收割&#xff1a;基于Hadoop的农产品价格信息智能分析 引言正文1. 数据获取与准备2. 数据清洗与处理3. Hadoop数据分析引擎的运用4. MySQL数据库的集成5. 创新性的可视化6. 结论与展望 结语 引言 随着信息技术的不断发展&#xff0c;农业领域也在数字化的浪潮…

三个算法题之---bjtu算法期末小测验

链接地址&#xff1a;https://algo.bjtu.edu.cn/contest?groupmy 题目1&#xff1a;Problem A. 加分二叉树 时间限制 1000 ms 内存限制 128 MB 题目描述设一个n个节点的二叉树tree的中序遍历为&#xff08;l,2,3,⋯,n&#xff09;&#xff0c;其中数字1,2,3,⋯,n为节点编号。每…

基于Spring Boot的美妆分享系统:打造个性化推荐、互动社区与智能决策

基于Spring Boot的美妆分享系统&#xff1a;打造个性化推荐、互动社区与智能决策 1. 项目介绍2. 管理员功能2.1 美妆管理2.2 页面管理2.3 链接管理2.4 评论管理2.5 用户管理2.6 公告管理 3. 用户功能3.1 登录注册3.2 分享商品3.3 问答3.4 我的分享3.5 我的收藏夹 4. 创新点4.1 …

【漏洞复现】冰峰VPN存在敏感信息泄露漏洞

漏洞描述 冰峰VPN log/system.log模块日志信息泄露漏洞 免责声明 技术文章仅供参考&#xff0c;任何个人和组织使用网络应当遵守宪法法律&#xff0c;遵守公共秩序&#xff0c;尊重社会公德&#xff0c;不得利用网络从事危害国家安全、荣誉和利益&#xff0c;未经授权请勿利…

MATLAB基础:从入门到熟悉

二十分钟快速入门Matlab Matlab是一款功能强大的建模软件&#xff0c;它在科学和工程领域被广泛使用。如果你已经具备一些计算机语言的基础知识&#xff0c;那么掌握Matlab的基础语法将会非常容易。下面我将用简单的语言给你介绍Matlab最常用的基础语法。 1、变量和赋值&#…

react怎么实现跨页面传参

在React中&#xff0c;可以使用路由参数、路由状态管理、Context API和本地存储等方式来实现跨页面传参。下面分别介绍这几种方法&#xff1a; 1、路由参数 在React Router中&#xff0c;可以通过路由参数来传递数据。在定义路由时&#xff0c;可以使用动态路由参数来接收参数…