用WaveX实现音频文件的录音
原文地址:https://blog.csdn.net/gongluck93/article/details/53096013
1、WaveInOpen
- 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
- );
2、至于pwfx,则比较关键,它指定了要以什么音频格式打开音频输入设备,它是一个结构WAVEFORMATEX:
- typedef struct {
- WORD wFormatTag; //可以在wFormatTag中指定一些压缩的音频格式,如G723.1,TURE DSP,等之类。不过一般都是选用WAVEFORMAT_PCM格式,
- //即未压缩的音频格式,至于压缩,可以在录完后调用下面将要谈到的ACM单独进行。
- WORD nChannels; //nChannels为声道数,1或者2。
- DWORD nSamplesPerSec; //nSamplesPerSec为每秒采样数,8000、11025、22050、44100为几个标准值。
- DWORD nAvgBytesPerSec; //每秒平均的字节数,在PCM方式中就等于nChannels*nSamplesPerSec*wBitsPerSample/8,
- //但对于其它的压缩的音频格式,由于很多压缩方式是按时间片进行的,如G723.1,就是以30ms为一个压缩单位,
- //这样,nAvgBytesPerSec只是一个大概的数字,并不准确,程序中的计算是不应该以这个量为准的。
- //这一点在下面的压缩音频输出和ACM音频压缩中非常重要。
- WORD nBlockAlign; //nBlockAlign是一个比较特殊的值,表示对音频处理时的最小处理单位,对于PCM非压缩,它就是wBitsPerSample*nChannels/8,
- //而对于非压缩格式,则表示压缩/解压处理的最小单位了,如G723.1,就是30ms的数据大小(20bytes或者24bytes)。
- WORD wBitsPerSample; //wBitsPerSample就是每采样值的位数,8或者16。
- WORD cbSize; //cbSize则是表示该WAVEFORMATEX的结构在标准的头部之后还有多少字节数,对于很多非PCM的音频格式,
- //有一些自己的定义格式参数,这些就紧跟在标准的WAVEFORMATEX后面,其大小就由cbSize指定。对于PCM格式而言,为0,或者忽略不检查。
- } WAVEFORMATEX;
1)从声卡获取的数据格式一般设置为WAVE_FORMAT_PCM,得到的是一种最原始的音频数值。采样率,采样位宽和采样通道数比较重要,尤其采样位宽--1此采样数据量的大小,这里采用16bits。
2)录音得到的数据是存放在自己设定的内存块处的,为了录音的连续,通常是用多个内存数据块。当一块数据内存满了之后,是通过消息响应的方式给指定的窗口或者回调函数。在回调函数中处理这些数据。
开启录音的代码段如下:
//启动录音
BOOL CAudioRec::StartRec()
{
BOOL bRet = FALSE; //启动线程
if(!StartThread())
{
goto Exit;
} //打开音频设备
if(!OpenDev())
{
goto Exit1;
} //准备缓存
if(!PrepareBuffer())
{
goto Exit2;
} //开始录音
if(!OpenRecord())
{
goto Exit3;
} bRet = TRUE;
goto Exit; Exit3:
//释放缓存
FreeBuffer(); Exit2:
//关闭录音设备
CloseDev(); Exit1:
//停止线程
StopThread(); Exit:
return bRet;
}
停止录音的代码段如下:
//终止录音
BOOL CAudioRec::StopRec()
{
//停止录音
if(!CloseRecord())
{
return FALSE;
} //暂停一会
Sleep(); //停止线程
if(!StopThread())
{
return FALSE;
} //释放录音分配内存
if(!FreeBuffer())
{
return FALSE;
} //关闭设备
if(!CloseDev())
{
return FALSE;
} return TRUE;
}
线程内数据处理的代码如下:
//线程回调函数
DWORD WINAPI CAudioRec::AudioInThreadProc(LPVOID lpParameter)
{
CAudioRec *pAudioRec = (CAudioRec *)lpParameter; // char buffer[1024]; MSG msg;
while(GetMessage(&msg,,,))
{
switch(msg.message)
{
//打开音频设备
case MM_WIM_OPEN:
break; //关闭录音设备
case MM_WIM_CLOSE:
break; //录音设备返回数据
case MM_WIM_DATA:
WAVEHDR *pWH = (WAVEHDR *)msg.lParam; waveInUnprepareHeader((HWAVEIN)msg.wParam,pWH,sizeof(WAVEHDR)); //dwBytesRecord表示此缓存中已有的数据大小
if(pWH->dwBytesRecorded != AUDIO_BUF_SIZE)
break; if(pAudioRec->m_pCallBackProc != NULL)
pAudioRec->m_pCallBackProc((BYTE *)pWH->lpData,AUDIO_BUF_SIZE,pAudioRec->m_dwUser); //获得的数据就在pWH->lpData,长度为pWH->dwBytesRecord
waveInPrepareHeader((HWAVEIN)msg.wParam,pWH,sizeof(WAVEHDR));
waveInAddBuffer((HWAVEIN)msg.wParam,pWH,sizeof(WAVEHDR));
}
} return msg.wParam;
}
其实数据处理的关键语句只有下面这一条:pAudioRec->m_pCallBackProc((BYTE *)pWH->lpData,AUDIO_BUF_SIZE,pAudioRec->m_dwUser);
它利用了一个函数指针,由调用者指定相应的处理函数。
今天下午调试了半天,卡在结束录音这个地方。其中语句的执行顺序很重要。
1)先停止录音即调用waveInStop()函数 2)停止线程StopThread() 3)释放为录音准备的缓存 4)关闭录音设备
我自己写的时候将关闭录音设备放在了停止线程的前面,在这里结束录音总是出错。
2018/4/28日增加以下内容:
封装更好的示例参见github项目,nadernt/whistle-recognizer,github地址:https://github.com/nadernt/whistle-recognizer/tree/7bfab2839150b0df7404886a4cf60db1b7be866b
参见此项目中WaveIOLib文件夹内容。
用WaveX实现音频文件的录音的更多相关文章
- C# NAudio录音和播放音频文件及实时绘制音频波形图(从音频流数据获取,而非设备获取)
下午写了一篇关于NAudio的录音.播放和波形图的博客,不太满意,感觉写的太乱,又总结了下 NAudio是个相对成熟.开源的C#音频开发工具,它包含录音.播放录音.格式转换.混音调整等功能.本次介绍主 ...
- iOS开发系列--音频播放、录音、视频播放、拍照、视频录制
--iOS多媒体 概览 随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制, ...
- iOS开发----音频播放、录音、视频播放、拍照、视频录制
随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制,还是对麦克风.摄像头的操 ...
- 音频播放、录音、视频播放、拍照、视频录制-b
随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制,还是对麦克风.摄像头的操 ...
- (原创)speex与wav格式音频文件的互相转换
我们的司信项目又有了新的需求,就是要做会议室.然而需求却很纠结,要继续按照原来发语音消息那样的形式来实现这个会议的功能,还要实现语音播放的计时,暂停,语音的拼接,还要绘制频谱图等等. 如果是wav,m ...
- S3C2416裸机开发系列19_Fatfs播放录像wav音频文件
S3C2416裸机开发系列19 Fatfs播放录像wav音频文件 国际象棋男孩 1048272975 多媒体资源,一般都是以文件的形式存储在固化存储器中.Fatfs所支持的fat32为windo ...
- iOS音频播放、录音、视频播放、拍照、视频录制
随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制,还是对麦克风.摄像头的操 ...
- DxPackNet 3.音频捕捉(录音)
用DxpackNet捕捉音频其实很简单 1.初始化控件 IDxMicrophCapture microphone; private void Form1_Load(object sender, Eve ...
- IOS音频1:之采用四种方式播放音频文件(一)AudioToolbox AVFoundation OpenAL AUDIO QUEUE
本文转载至 http://blog.csdn.net/u014011807/article/details/40187737 在本卷你可以学到什么? 采用四种方法设计应用于各种场合的音频播放器: 基于 ...
随机推荐
- (2015大作业)茹何优雅的手写正则表达式引擎(regular expression engine
貌似刚开学的时候装了个逼,和老师立了个flag说我要写个正则表达式引擎,然后学期末估计老师早就忘了这茬了,在历时3个月的懒癌发作下,终于在这学期末deadline的时候花了一个下午加晚上在没有网的房间 ...
- 了不得,我可能发现了Jar 包冲突的秘密
一.前言 这篇是类加载器相关的第三篇: 实战分析Tomcat的类加载器结构(使用Eclipse MAT验证) 还是Tomcat,关于类加载器的趣味实验 昨天下午刚写了篇 类加载器相关的,晚上想着验证个 ...
- Python入门--12--函数与变量
python只有函数没有过程 函数有运行完了之后会有返回值.过程没有 def back(): return 1,'gg',2 #会有返回值(1,'gg',2) #注意默认返回元祖 一.全局和局部变量 ...
- js Math [ 随机数、绝对值、四舍五入、进一取整、舍去取整、最大值、最小值、圆周率 ]
<script> /* 数学对象:Math */ with (document) { write('<br>-3.5的绝对值:'+Math.abs(-3.5)); write( ...
- UVA11825 Hackers' Crackdown
题目描述 PDF 输入输出格式 输入格式: 输出格式: 输入输出样例 输入样例#1: 3 2 1 2 2 0 2 2 0 1 4 1 1 1 0 1 3 1 2 0 输出样例#1: Case 1: 3 ...
- Ubuntu 16.04下在Shell终端下使用nautilus快速打开窗口文件夹
Ubunut 16.04默认使用nautilus进行管理资源文件夹,nautilus默认是支持参数传递的. 使用: nautilus /dirurl 打开当前文件夹(可以使用$PWD代替): naut ...
- 《Java虚拟机原理图解》 1.2.3、Class文件中的常量池详解(下)
CONSTANT_Fieldref_info, CONSTANT_Name_Type_info) 一般而言,我们在定义类的过程中会定义一些 field 字段,然后会在这个类的其他地方(如方法中)使用到 ...
- 《深入理解mybatis原理》 MyBatis缓存机制的设计与实现
本文主要讲解MyBatis非常棒的缓存机制的设计原理,给读者们介绍一下MyBatis的缓存机制的轮廓,然后会分别针对缓存机制中的方方面面展开讨论. MyBatis将数据缓存设计成两级结构,分为一级缓存 ...
- Java截取视频首帧并旋转正向
package test; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Image; import j ...
- java cocurrent并发包
1. java.util.concurrent - Java 并发工具包Java 5 添加了一个新的包到 Java 平台,java.util.concurrent 包.这个包包含有一系列能够让 Jav ...