一、数字音频基础知识

  • Fourier级数:

任何周期的波形可以分解成多个正弦波,这些正弦波的频率都是整数倍。级数中其他正线波的频率是基础频率的整数倍。基础频率称为一级谐波。

  • PCM:

pulse code modulation,脉冲编码调制,即对波形按照固定周期频率采样。为了保证采样后数据质量,采样频率必须是样本声音最高频率的两倍,这就是Nyquist频率。
样本大小:采样后用于存储振幅级的位数,实际就是脉冲编码的阶梯数,位数越大表明精度越高,这一点学过数字逻辑电路的应该清楚。

  • 声音强度:

波形振幅的平方。两个声音强度上的差常以分贝(db)为单位来度量,

  • 计算公式如下:

20*log(A1/A2)分贝。A1,A2为两个声音的振幅。如果采样大小为8位,则采样的动态范围为20*log(256)分贝=48db。如果样本大小为16位,则采样动态范围为20*log(65536)大约是96分贝,接近了人听觉极限和痛苦极限,是再线音乐的理想范围。windows同时支持8位和16位的采样大小。

二、相关API函数,结构,消息
对于录音设备来说,windows 提供了一组wave***的函数,比较重要的有以下几个:

  • 打开录音设备函数
MMRESULT waveInOpen(
LPHWAVEIN phwi,            //输入设备句柄
UINT uDeviceID,            //输入设备ID
LPWAVEFORMATEX pwfx,       //录音格式指针
DWORD dwCallback,          //处理MM_WIM_***消息的回调函数或窗口句柄,线程ID
DWORD dwCallbackInstance,
DWORD fdwOpen              //处理消息方式的符号位
);
  • 为录音设备准备缓存函数
MMRESULT waveInPrepareHeader(  HWAVEIN hwi,  LPWAVEHDR pwh, UINT bwh );  
  • 给输入设备增加一个缓存
MMRESULT waveInAddBuffer(  HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh );  
  • 开始录音
MMRESULT waveInStart(  HWAVEIN hwi  );  
  • 清除缓存
MMRESULT waveInUnprepareHeader( HWAVEIN hwi,LPWAVEHDR pwh, UINT cbwh);  
  • 停止录音
MMRESULT waveInReset( HWAVEIN hwi );  
  • 关闭录音设备
MMRESULT waveInClose( HWAVEIN hwi );  
  • Wave_audio数据格式
typedef struct {
WORD  wFormatTag; //数据格式,一般为WAVE_FORMAT_PCM即脉冲编码
WORD  nChannels; //声道
DWORD nSamplesPerSec; //采样频率
DWORD nAvgBytesPerSec; //每秒数据量
WORD  nBlockAlign;
WORD  wBitsPerSample;//样本大小
WORD  cbSize;
} WAVEFORMATEX;  
  • waveform-audio 缓存格式 
typedef struct {
LPSTR  lpData; //内存指针
DWORD  dwBufferLength;//长度
DWORD  dwBytesRecorded; //已录音的字节长度
DWORD  dwUser;
DWORD  dwFlags;
DWORD  dwLoops; //循环次数
struct wavehdr_tag * lpNext;
DWORD  reserved;
} WAVEHDR;  
  • 相关消息 
MM_WIM_OPEN:打开设备时消息,在此期间我们可以进行一些初始化工作
MM_WIM_DATA:当缓存已满或者停止录音时的消息,处理这个消息可以对缓存进行重新分配,实现不限长度录音
MM_WIM_CLOSE:关闭录音设备时的消息。

相对于录音来说,回放就简单的多了,用到的函数主要有以下几个:

  • 打开回放设备 
MMRESULT waveOutOpen(
LPHWAVEOUT phwo,
UINT uDeviceID,
LPWAVEFORMATEX pwfx,
DWORD dwCallback,
DWORD dwCallbackInstance,
DWORD fdwOpen
);  
  • 为回放设备准备内存块 
MMRESULT waveOutPrepareHeader(
HWAVEOUT hwo,
LPWAVEHDR pwh,
UINT cbwh
);
  • 写数据(放音) 
MMRESULT waveOutWrite(
HWAVEOUT hwo,
LPWAVEHDR pwh,
UINT cbwh
);

相应的也有三个消息,用法跟录音的类似:

三、程序设计

一个录音程序的简单流程:

打开录音设备waveInOpen===>准备wave数据头waveInPrepareHeader===>
准备数据块waveInAddBuffer===>开始录音waveInStart===>停止录音(waveInReset) ===>
关闭录音设备(waveInClose)

当开始录音后当buffer已满时,将收到MM_WIM_DATA消息,处理该消息可以保存已录好数据。

回放程序比这个要简单的多: 

打开回放设备waveOutOpen===>准备wave数据头waveOutPrepareHeader===>写wave数据waveOutWrite===>
停止放音(waveOutRest) ===>关闭回放设备(waveOutClose)

如何处理MM消息:

MSDN告诉我们主要有 CALLBACK_FUNCTION、CALL_BACKTHREAD、CALLBACK_WINDOW 三种方式,常用的是
Thread,window方式。

线程模式
waveInOpen(&hWaveIn,WAVE_MAPPER,&waveform,m_ThreadID,NULL,CALLBACK_THREAD),我们可以继承MFC的CwinThread类,只要相应的处理线程消息即可。
MFC线程消息的宏为:

    ON_THREAD_MESSAGE,

可以这样添加消息映射:

    ON_THREAD_MESSAGE(MM_WIM_CLOSE, OnMM_WIM_CLOSE)  

窗口模式
类似于线程模式,参见源程序即可。

转自:http://www.vckbase.com/document/viewdoc/?id=904

原文代码在此地址中。

基于API的录音机程序相关推荐

  1. 你也可以玩转Skype -- 基于Skype API开发外壳程序入门

    原文:你也可以玩转Skype -- 基于Skype API开发外壳程序入门 Skype是目前这个星球上最厉害的IM+VOIP软件,Skype现在已经改变了全球2.8亿人的生活方式.你,值得拥有! :) ...

  2. libvirt 用c语言编译,基于C语言libvirt API简单小程序

    libvirt API简单小程序 1.程序代码如下 #include #include int getDomainInfo(int id) { virConnectPtr conn = NULL; v ...

  3. 【ReactiveX】基于Golang pmlpml/RxGo程序包的二次开发

    基于Golang pmlpml/RxGo程序包的二次开发[阅读时间:约20分钟] 一.ReactiveX & RxGo介绍 1.ReactiveX 2.RxGo 二.系统环境&项目介绍 ...

  4. 最简单的基于FFMPEG的Helloworld程序

    学习雷神的FFMPEG入门教程,本文基于命令行实现. 文件结构 G:\Coding\FFMpeg\Proj\Console>dir驱动器 G 中的卷没有标签.卷的序列号是 0FD5-0CC8G: ...

  5. 基于持久化的wordcount程序 foreachRDD

    基于持久化的wordCount程序!中途遇到了一个坑! 自己手动封装一个静态线程池,使用RDD的foreachPartition操作,并且在该操作内部,从静态连接池中,通过静态方法,获取一个连接,使用 ...

  6. jvm虚拟机 基于栈_守护基于JVM的应用程序

    jvm虚拟机 基于栈 部署体系结构设计是任何定制服务器端应用程序开发项目的重要组成部分. 由于其重要性,部署架构设计应尽早开始,并与其他开发活动一起进行. 部署体系结构设计的复杂性取决于许多方面,包括 ...

  7. spring boo_为您的下一个基于Spring的应用程序考虑使用spring-boot的原因!

    spring boo Spring-boot提供了一种创建基于Spring的应用程序的快速方法. 对于下一个项目,有一些非常令人信服的理由考虑使用Spring-boot: 原因1:使用spring-b ...

  8. java中使用es的dsl_基于DSL的基于图论的Java程序中输入图数据的方法

    java中使用es的dsl 我们大多数人已经编写了一些处理图论算法的程序,例如找到两个顶点之间的最短路径,找到给定图的最小生成树等等. 在这些算法的每一种中,表示图形的编程方式是使用邻接矩阵或邻接列表 ...

  9. 守护基于JVM的应用程序

    部署体系结构设计是任何定制服务器端应用程序开发项目的重要组成部分. 由于其重要性,部署架构设计应尽早开始,并与其他开发活动一起进行. 部署体系结构设计的复杂性取决于许多方面,包括所提供服务的可伸缩性和 ...

最新文章

  1. 做了几道Linux笔试题1
  2. Windows下载Android源代码
  3. 10分钟零基础带你入门Ribbon小项目-啥?小白都能看懂?
  4. QT学习:多线程控制
  5. 由web程序出现乱码开始挖掘(Bom头、字符集与乱码)
  6. InnoDB Spin rounds per wait在32位机器上可能为负
  7. Python学习day12(生成器,列表/生成器推导式)
  8. 周末给女友讲了遍加密算法,没想到...
  9. 杰克·韦尔奇语录-世界第一CEO
  10. 你会几种“复制”文本的方式?----浅谈I/O流
  11. Python入门--for循环
  12. Java学习笔记(五):Complex类的设计及加减乘除运算的实现
  13. 爱情、面包论——真正的爱情
  14. java排他_排他文件锁实现(Java版本)
  15. Batch Size 对训练的影响
  16. 一文了解各大数据库查询语言(Gremlin vs Cypher vs nGQL操作篇
  17. 危险的外围设备:Windows和Linux系统的计算机内部安全隐患研究
  18. 【三】零基础入门深度学习:卷积神经网络基础之初识卷积
  19. 无锁实现线程间共享数据
  20. Java网络编程:socket与Netty

热门文章

  1. 历史最全开放语音/音频数据集整理分享
  2. 【Mecanum wheel】初理解
  3. 求好看简洁的PPT模版
  4. 锁屏界面的小锁图标UI异常,竖屏不居中,显示在右边。锁屏小锁图标在底部会与提示文字重叠。
  5. 论文解读 | Transformer 原理深入浅出
  6. linux高性能服务器编程学习总结(二)
  7. 制作linux红帽光盘刻录,linux下mkisofs制作光盘映像cdrecord刻录光盘
  8. 每周分享第 22 期
  9. 简单 PHP + MySQL 数据库动态网站制作
  10. `Computer-Algorithm` 差分约束系统,不等式组