windows录音程序原理
依赖条件:1 #pragma comment ( lib, "winmm.lib" )
音频的输入大体分三步
1 打开设备 -----waveInOpen(打开一个音频输入设备)、
2 开始录音------waveInStart开始录音
3关闭设备-------waveInClose关闭录音。之前调用一下waveInReset,这样可以清掉尚在等待录音的缓冲区
常用的相关API为:
waveInOpen(打开一个音频输入设备)
waveInPrepareHeader(为一个即将在waveInAddBuffer中调用的输入缓冲区准备头部)
waveInAddBuffer(添加一个输入用的数据缓冲区)
waveInStart(开始录音)
waveInClose(关闭音频输入设备)等几个,以及需要在waveInOpen中指定的一个回调函数或者线程,其作用是在一个数据缓冲区被录满后被调用,以对这些数据进行处理,和其他一些相关的操作。注意这里的一个数据缓冲区。
下面详细说明他们相对应的关系。
1---------------waveInOpen
MMRESULT waveInOpen( LPHWAVEIN phwi, //phwi是返回的句柄存放地址
UINT uDeviceID, // uDeviceID是要打开的音频设备ID号,一般都指定为WAVE_MAPPER
LPWAVEFORMATEX pwfx,
DWORD dwCallback, //dwCallback则为指定的回调函数或线程,窗口等的地址
DWORD dwCallbackInstance, // dwCallbackInstance为需要向回调函数或线程送入的用户参数
DWORD fdwOpen // fdwOpen指定回调方式:CALLBACK_FUNCTION, CALLBACK_THREAD和CALLBACK_WINDOW
);
至于pwfx,则比较关键,它指定了要以什么音频格式打开音频输入设备, 它是一个结构WAVEFORMATEX:
typedef struct { WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
WORD wBitsPerSample;
WORD cbSize;
} WAVEFORMATEX;
可以在wFormatTag中指定一些压缩的音频格式,如G723.1,TURE DSP,等之类。不过一般都是选用WAVEFORMAT_PCM格式,即未压缩的音频格式,至于压缩,可以在录完后调用下面将要谈到的ACM单独进行。
nChannels为声道数,1或者2。
nSamplesPerSec为每秒采样数,8000、11025、22050、44100为几个标准值。
nAvgBytesPerSec为每秒平均的字节数,在PCM方式中就等于nChannels*nSamplesPerSec*wBitsPerSample/8,但对于其它的压缩的音频格式,由于很多压缩方式是按时间片进行的,如G723.1,就是以30ms为一个压缩单位,这样,nAvgBytesPerSec只是一个大概的数字,并不准确,程序中的计算是不应该以这个量为准的。这一点在下面的压缩音频输出和ACM音频压缩中非常重要。
nBlockAlign是一个比较特殊的值,表示对音频处理时的最小处理单位,对于PCM非压缩,它就是wBitsPerSample*nChannels/8,而对于非压缩格式,则表示压缩/解压处理的最小单位了,如G723.1,就是30ms的数据大小(20bytes或者24bytes)。
wBitsPerSample就是每采样值的位数,8或者16。
cbSize则是表示该WAVEFORMATEX的结构在标准的头部之后还有多少字节数,对于很多非PCM的音频格式,有一些自己的定义格式参数,这些就紧跟在标准的WAVEFORMATEX后面,其大小就由cbSize指定。对于PCM格式而言,为0,或者忽略不检查。
这样,指定了这些参数后,你应该就能够打开音频输入设备了。下面要做的事情就是准备几个用做录音的缓冲区。常准备多个缓冲区,并在回调中循环使用。对于缓冲区,得使用waveInPerpareHeader准备一下头部,这个API比较简单,如果你是循环使用缓冲区,对每个缓冲区也只需要调用一次waveInPrepareHeader。为什么要使用一次就可以。参看waveInPerpareHeader说明就明白。此函数功能就是定位缓冲区的数据区地址,和数据大小。以便为系统所用。
A)
首先得确定一下需要用什么回调方式,即在某个时间片的音频数据被录完后,Windows将通过这个回调来激活对这些数据的处理过程,一般用到的无非是FUNCTION、THREAD和EVENT这几类,而比较方便简单的就是FUNCTION和THREAD了。FUNCTION方式是指Windows会调用你这个函数,而THREAD则是由 Windows来激活你所指定的线程。这些都在waveInOpen中指定。
b)
一切准备好之后,就可以调用waveInAddBuffer和waveInStart开始录音了,只要你一调用这个waveInStart,录音就开始了,即使这个缓冲区录满之后你没有加入新的缓冲区进去,录音也不会停,只是这中间的语音数据全都丢了。当通过 waveInAddBuffer送入的缓冲区被录满后,Windows就会通过你在waveInOpen中指定的方式进行回调,在回调中把录好的语音数据取出来,并且,如果还想继续录音的话,得将下一个缓冲区添加进去。考虑到这个处理是有时间延迟的,而且音频对时间很敏感,
一般都要先预加入若干个缓冲区,有人提出:比如,一共定义了8个缓冲区,而为了保险起见,最好保证任一时刻至少有3个缓冲区可被录音使用,那么在开始录音时,则先加入4个缓冲区,然后在回调中,如果当前录好的缓冲区第n个,则对第(n+4)%8调用waveInAddBuffer,这时,还有第(n+1)%8,(n+2)%8, (n+3)%8这三个缓冲区可用,即基本上就可以保证所录得音频中不会有断开的间隔。比如0,1,2,3这些个先加入,当0好的时候对4,5 ,6 ,7调用waveInAddBuffer。
如此这样何不:开始的时候把8个全部放入缓冲区,当一个缓冲区满后调用回调,处理后立即把这个缓冲区重用,继续添加到缓冲区队列中。不更简单明了。如下
mmReturn = ::waveInPrepareHeader ( m_hRecord, pHdr, sizeof(WAVEHDR) ); //准备
mmReturn = ::waveInAddBuffer ( m_hRecord, pHdr, sizeof(WAVEHDR) );//添加
注意这两步都是在回调,或者线程中处理的。
c)
想结束录音时,最好在waveInClose之前调用一下waveInReset,这样可以清掉尚在等待录音的缓冲区,这里常见的问题是等待的缓冲区清理了,可是正在用的缓冲区怎么办?如果这个时候就用waveInClose,那么系统会出错。解决方法一:在回调函数中注意,一个缓冲区满后,不要再用waveInAddBuffer增加缓存,当缓冲区用到1的时候调用waveInReset清掉尚在等待录音的缓冲区继续waveInClose。
总结上面的注意3点:回调的选取,注意缓冲区的原理,注意结束的处理
windows waveform方式实现录音要通过这么几步:(注意顺序!!)
一、打开录音设备
waveinopen()函数
注意,调用之前要填写好wav头信息(包含采样率、采样位数等);还要定义好回调函数等,回调函数的解释后面讲。
二、准备好录音缓存空间
waveinprepareheader()函数
这一步为了准备好将要送入录音设备的缓存,以便之后可以供之使用。
一般至少需要准备两块缓存。因为录音不能间断,当一块填满时没有时间等待你去送入下一块缓存,所以必须提前就准备好。
三、将缓存送入录音设备
waveinaddbuffer()函数
将缓存送入录音设备,供之存入已录下的音频。开始录音时,应至少送入两块不同的缓存,即调用两次这个函数。之后为了不致录音产生间断,应保证至少有一块缓存在录音时为空,以备衔接。
四、开始录音
waveinstart()函数
当以上的工作都准备好时,便可调用此函数开始录音了。一旦调用,录音设备便立即录音并存入已经送来的缓存块内,当被送来的有多个缓存块时,按照FIFO的原则向缓存块内存入录音数据。此函数执行之后可以执行一个while()循环,来等待录音设备录音。为了减少cpu使用率,可以在循环中加人sleepex(x,TRUE),x单位ms,TRUE必须要有。
每个缓冲块存满时,会产生一个回调信号,并调用回调函数(或回调窗口等,具体定义在waveinopen函数内,这里只讲回调函数的情况);回调信号自动被回调函数接收,回调函数根据回调信号来执行各种相应的操作。回调函数执行完后,程序跳回到原来执行位置继续执行。回调函数的具体如下:
回调信号一般有三个,对应着三种回调函数被调用的情况:
1、 WIM_OPEN
当执行waveinopen()函数时,会调用回调函数,并产生这个回调信号。代表录音设备已经打开。在这次回调函数的调用中,可以自己设定一些操作,也可以没有操作。
2、 WIM_DATA
当每块缓存块填满时,产生这个回调信号,并调用回调函数。在这次调用中,回调函数应当完成这样的工作,以便录音连续进行:
将存满的缓存块处理,例如存入文件,或送入其他设备;
向录音设备送入新的缓存块;录音设备任何时刻应当拥有不少于2个的缓存块,以保证录音不间断性。
3、 WIM_CLOSE
当调用waveinclose函数时,会产生这个回调信号,代表录音设备关闭成功。这次回调函数调用中,可以执行相应的一些关闭文件保存信息等等的操作,自定义。
五、停止录音,关闭设备
waveinstop()停止录音
waveinreset()复位
waveinclose()关闭设备
依次调用这些函数,来结束录音。
最后,注意在代码开头要包含windows.h和mmsystem.h两个头文件,还要加人库winmm.lib,用#pragma comment(lib,”winmm.lib”)即可。
主要顺序就是这些,注意每一步要完成的工作,一旦没有按顺序执行或者没有把每步应当完成的工作做完,录音是不能够启动的
windows录音程序原理相关推荐
- 【系统篇】从int 3探索Windows应用程序调试原理
http://www.cnblogs.com/xuanyuan/p/3998408.html 探索调试器下断点的原理 在Windows上做开发的程序猿们都知道,x86架构处理器有一条特殊的指令--in ...
- 比较windows phone程序启动和android程序启动原理
windows phone 程序是如何启动的了,他和android程序有什么区别,我们重点从native code 层面来分析 在windows phone 程序启动的时候是: 在XAML中使用应用程 ...
- [视频]用SQL Server Compact创建简单的Windows应用程序
今天下午录制了一段 SQL Server Compact 应用程序开发的入门视频,帮助园子里的朋友打开 SQL Server Compact 开发的大门. 技术等级:100 准备环境:Visual S ...
- 用vc++穷举windows应用程序密码
一.引言 随着计算机信息技术的发展,人们越来越重视信息的安全性,信息数据的安全保密已经成为影响计算机发展的一个重要课题.机密文件.商业情报.银行账号.网络密码.科技成果.包括私人信件等等,都成了用户为 ...
- 用vc++穷举windows应用程序密码(上)
2007年10月12日 02:14:00 一.引言 随着计算机信息技术的发展,人们越来越重视信息的安全性,信息数据的安全保密已经成为影响计算机发展的一个重要课题.机密文件.商业情报.银行账号.网络密码 ...
- 提高微信小程序的应用速度的常见方式有哪些? 小程序怎么实现下拉刷新? 简述微信小程序原理? 小程序的发布流程(开发流程)分析下微信小程序的优劣势?小程序授权登录流程? 小程序支付如何实现
小程序部分常见面试题 提高微信小程序的应用速度的常见方式有哪些? 提高页面加载速度 用户行为预测 减少默认data的大小 组件化方案 分包预下载 小程序与原生App相比优缺点? 优点: 基于微信平台开 ...
- XMLHTTP小偷程序原理
小偷程序原理和简单示例 发表:2004-4-13 164720 出处:你的博客网(yourblog.org) 现在网上流行的小偷程序比较多,有新闻类小偷,音乐小偷,下载小偷,那么它们是如何做的呢,下面 ...
- (转)Windows应用程序中动态的控制输入法
在Windows系统中一般都安装了至少三种输入法,在输入数据时常常会切换输入法,虽然Windows系统提供了切换快捷健,但对输入工作还是带来了不少麻烦.如果在应用程序中为用户提供智能输入法自动切换,那 ...
- 基于ALSA的WAV播放和录音程序
本文转载博客:http://blog.csdn.net/azloong/article/details/6140824 ---------------------------------------- ...
最新文章
- 微信公共平台消息回复类
- 委托、事件的个人理解
- SharePoint关于publish page, WiKi page, Web part page区别
- c语言传入的指针无返回值,c语言 关于指针注意事项
- 前端学HTTP之客户端识别和cookie
- 南阳oj-----懒省事的小明(set)
- 查看linux系统语言并修改
- 51单片机c语言算法大全,C语言实现51单片机中的PID算法
- SoC,SiP,IP和Chiplet的区别
- excel 删除大量空白行
- 长假之后,Scrum团队应该修改Sprint的结束时间吗?
- 在Status状态栏中的出现Out of date shapes问题解决方式
- win10无法防问其他计算机没有权限,win10系统访问磁盘共享没有权限的解决方案...
- 如何将ANSYS19 Structural 图形界面背景底色更改为白色
- Global Sensing and Measurements Reuse for Image Compressed Sensing
- 班级网站(网页设计实验)
- 艾永亮:B站破壁出圈,同是弹幕视频网站,为什么倒下的是A站?
- css动画中文字慢慢显示,利用定时器和css3动画制作文字依次渐变显示的效果
- java反射字段6,java反射判断字段类型
- 区块链蕴含的变革力量
热门文章
- 图片复制word java_java poi实现word导出(包括word模板的使用、复制表格、复制行、插入图片的使用)...
- C语言斐波那切数列数列求和
- wegame显示不出区服务器,wegame无法显示网页怎么办?腾讯wegame无法显示网页的三种解决方法...
- 适合苹果的蓝牙耳机推荐,音质超好的蓝牙耳机推荐
- 哪种蓝牙耳机比较好?2022TWS耳机推荐
- C和C++的区别点汇总
- php药膳 源码,5款药膳方治疗关节炎
- python人像精细分割_基于UNet网络实现的人像分割 | 附数据集
- 和在java和c语言中的那些事
- 朴素贝叶斯分类(python实现)