找回密码
 注册
搜索
查看: 4646|回复: 0

简单录、放音并保存为wav文件程序

[复制链接]
发表于 2007-11-30 13:43:24 | 显示全部楼层 |阅读模式
作者:任雪景、文娟

, E3 l# Y& a7 v7 r      下载源代码5 }- a8 K5 Z* F0 v- S9 `
        
$ i: z4 [% U" U+ \$ S) S# }" q        引言
# ?4 L* }4 A8 n5 l9 U. q" X* f        我是C++的初学者,入门都要靠VCKBASE,好在里面有很多适合于初学者的例子,让我少走了很多弯路,为了回馈大家,我也把我最近刚完成的一个简单的小程序提供给大家,让那些曾经和我一样徘徊在C++大门之外的人能快些掌握要领,大家不妨看一看。9 V& P* p+ D- {
        本文以VC知识库第26期 栾义明 先生的《基于API的录音机程序》为基础的,在此深表感谢!相同之处不再重复,我在此基础上增加了将录音保存为wav文件的格式,便于大家参考。
1 [$ l8 t$ r) X  \7 `基本步骤及思想:设定音频采集参数(采样率、声道等),打开音频设备、准备wave数据头和开辟缓存,操作采集的数据并保存为wav文件。设定音频回放参数,打开回放设备、准备wave数据头和写wave数据。另外样本程序需包含#include <mmsystem.h>和#pragmacomment(lib,"WINMM.LIB")多媒体支持。
4 y2 k6 H4 [1 T$ s4 ?        在介绍程序前,需要你对wave文件的格式和相关一些基础概念有所了解,这些均可以在msdn中查找,为方便理解,我们将其整理,如果对这些基础知识已有所了解,可以跳过。
; n6 c2 b$ ?. x        % c  Y6 O6 h" z) m# I6 |
      概念1、定义波形数据格式
9 k9 u* F* [9 h7 o( A      typedef struct{WORD  wFormatTag; : E' g* r. U3 Z
          WORD nChannels; 0 b! ^8 g( A) P2 I; Y" c+ e
          DWORD nSamplesPerSec; % f- |2 V/ c5 d7 S& k5 H$ n1 W. l
          DWORD nAvgBytesPerSec;$ k0 q" w- H, O4 a8 ^0 H
          WORD  nBlockAlign; . @0 T( v3 A) `; |- E& R' G5 i' P) J
          WORD wBitsPerSample;
& Z9 ?/ b. R: y# Q! U* c          WORD  cbSize; } WAVEFORMATEX;      具体参数解释如下:: p- [9 Q6 u6 v' _2 J$ o
      wFormatTag:波形数据的格式,定义在MMREG.H文件中5 d! T* S. C: _! G1 `
      nChannels:波形数据的通道数:单声道或立体声2 X/ W. ?6 E+ L$ e% n
      nSamplesPerSec:采样率,对于PCM格式的波形数据,采样率有8.0 kHz,11.025kHz,22.05 kHz,44.1 kHz等! {0 j; s8 e* o- B8 ^
      nAvgBytesPerSec:数据率,对于PCM格式的波形数据,数据率等于采样率乘以每样点字节数$ N6 B9 _5 t) P7 n% E3 N
      nBlockAlign:每个样点字节数( g( `3 L' ]8 U/ B# P! f- c
      wBitsPerSample:采样精度,对于PCM格式的波形数据,采样精度为8或16
% r; K! F* m  h( R4 V2 _0 j" a* r2 d      cbSize:附加格式信息的数据块大小9 P( {+ d! E8 T+ Q4 t. {! ?
      概念2、定义设备头结构; k1 b2 K4 t# T
    WAVEHDR定义了指向波形数据缓冲区的设备头。typedef struct { LPSTR lpData; 9 j# r9 O7 a$ w8 w5 k
        DWORD dwBufferLength;
* r/ \$ Z2 A; I6 a: E8 s+ G: {        DWORD dwBytesRecorded; . @4 d2 A7 Y: Y. ?" O0 K
        DWORD dwUser;
" u1 ~, H' p& k        DWORD dwFlags; 0 S: h; @$ U% v" w: W
        DWORD dwLoops;
1 Z( o9 s6 k5 K  Z5 G( |: o        struct wavehdr_tag * lpNext;
5 p  e' v) U+ |' `        DWORD reserved; } WAVEHDR;     lpData:波形数据的缓冲区地址8 k$ ^3 O( C" t. [+ a% P
    dwBufferLength:波形数据的缓冲区地址的长度
: E9 P* m/ z& S7 g+ E* S: Q7 x    dwBytesRecorded:当设备用于录音时,标志已经录入的数据长度# W+ N# s$ f: S8 f' f7 e/ S3 F+ ~5 @4 O
    dwUser:用户数据0 |5 [( Z5 m9 }$ L
    dwFlags:波形数据的缓冲区的属性
. E- e$ c3 e! p% I    dwLoops:播放循环的次数,仅用于播放控制中* n- w2 L9 F5 K4 r$ Z* D
    lpNext和reserved均为保留值
* ]; }6 D( k9 b8 _- \    注意:上述结构体以及我们在程序中所使用到的“HWAVEIN””HWAVEOUT”结构体均是系统已经存在的,我们只需要对其进行赋值即可。8 f$ ?* `  J2 A3 ]5 i
    概念3、消息处理函数) D0 v* G0 i5 u& U- y# s
    MM_WIM_OPEN    //设备的打开
: `% ?! d( M1 P" V; X: g& M4 S    MM_WIM_DATA    //设备数据的采集及操作. M6 N' L& X) V. Y" _
    MM_WIM_CLOSE   //设备的关闭7 d) ?, ^7 L& E" `
    相应回放设备的消息分别为MM_WOM_OPEN,MM_WOM_DATA,MM_WOM_CLOSE.
' r! M6 A5 A$ ?- W5 i6 @    注意:消息处理函数是消息自我驱动的,不需要我们的人为干预。比如:当我们打开设备时,系统会自动调用MM_WIM_OPEN,当我们将数据添加到缓冲区,而缓冲区满时,系统会自动调用MM_WIM_DATA,我们所需要做的,就是对该函数编好相应的源代码。6 V  S$ K9 n" v: }7 w
    现在,我们进入正题:如何实现一个录音机。
1 U/ V+ W8 x- ^+ O    1 [7 T: y# e6 [. X7 q1 T+ L1 \3 i
    ⑴先对WAVEFORMATEX结构体进行赋值,然后为缓冲区分配内存pBuffer1=(PBYTE)malloc(INP_BUFFER_SIZE);3 g/ m  H' D: ~; A% }1 ]
pBuffer2=(PBYTE)malloc(INP_BUFFER_SIZE);# `  B0 R3 C9 h# n# e% c( Z
对设备头结构体分配内存pWaveHdr1=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));
0 k* A3 j( i5 NpWaveHdr2=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));/ z* W3 ?9 L8 `4 j" b
然后使用wave音频相关函数对输入数据进行操作:5 c$ u" t# s+ a  X: }( f
  R  d& W6 R3 n6 T' n  ?  u
①为波形输入设备准备缓冲区waveInPrepareHeader(hWaveIn,pWaveHdr1,sizeof(WAVEHDR));1 K& g( a! m, l/ @
waveInPrepareHeader(hWaveIn,pWaveHdr2,sizeof(WAVEHDR));
' n  }) u  g# @+ v1 q, G②为波形输入设备添加缓冲区waveInAddBuffer (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;
+ j1 r7 s3 p2 ?  G) GwaveInAddBuffer (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;
1 H% h& ?0 F9 F, R- }③启动声音输入设备,将输入数据写入内存waveInStart (hWaveIn) ;⑵编写消息处理函数,其中,MM_WIM_DATA函数是本程序的核心。其主要作用是将输入数据另行保存在一缓冲区内(pSaveBuffer),该缓冲区的长度将随着已录入数据的大小而增加,从而实现保存输入话音数据的功能。同时,可将缓冲区内数据保存为wav文件。其具体实现如下:CFile m_file;
- o5 T! M4 ?9 Z. ^: XCFileException fileException;
+ W+ T* w4 l( v. l& k$ S5 GCString m_csFileName= "F:\\audio.wav";//保存路径9 E7 O: c- j% k& g- J/ z
m_file.Open(m_csFileName,CFile::modeCreate|CFile::modeReadWrite, &fileException);
5 Q7 m. z! c8 c* DDWORD m_WaveHeaderSize = 38;
! ]) C: N/ |6 J' e& }  X- QDWORD m_WaveFormatSize = 18;
5 E: b* s8 \) p4 g% x* qm_file.SeekToBegin();6 k* q8 G$ D& N7 r. u$ g
m_file.Write("RIFF",4);
. b4 ?# A3 c+ F2 w- V) x6 tunsigned int Sec=(sizeof pSaveBuffer + m_WaveHeaderSize);5 a4 T4 f+ E9 j2 C- q
m_file.Write(&Sec,sizeof(Sec));
" |" o9 @$ O1 b* E( w8 Q7 p) tm_file.Write("WAVE",4);. J% n) \" n9 L4 M5 {
m_file.Write("fmt ",4);
' _) I8 K$ H+ t- q; hm_file.Write(&m_WaveFormatSize,sizeof(m_WaveFormatSize));; b4 f! w# N" G/ Y0 d
m_file.Write(&waveform.wFormatTag,sizeof(waveform.wFormatTag));$ s6 w( j( t) v
m_file.Write(&waveform.nChannels,sizeof(waveform.nChannels));/ ^: o! P' ^7 M# G6 A9 {
m_file.Write(&waveform.nSamplesPerSec,sizeof(waveform.nSamplesPerSec));
: X0 z2 E0 ^9 P$ vm_file.Write(&waveform.nAvgBytesPerSec,sizeof(waveform.nAvgBytesPerSec));
6 I  P3 ~7 g7 }& P( qm_file.Write(&waveform.nBlockAlign,sizeof(waveform.nBlockAlign));; f+ Z* A7 Z1 Y, \6 z( k* P5 H
m_file.Write(&waveform.wBitsPerSample,sizeof(waveform.wBitsPerSample));1 i4 I  W/ Q0 u4 {8 t
m_file.Write(&waveform.cbSize,sizeof(waveform.cbSize));- F2 c( Z5 G1 e" l6 p3 M( |
m_file.Write("data",4);
- v7 J5 J" i0 W) |, U( Nm_file.Write(&dwDataLength,sizeof(dwDataLength));
3 }* L3 F( h/ j, w8 M8 Dm_file.Write(pSaveBuffer,dwDataLength);
: C5 w0 m+ O0 w& e- t& rm_file.Seek(dwDataLength,CFile::begin);
2 y% z0 R2 @8 z7 W# rm_file.Close();# S. B; s% c! S$ x+ }$ g  J
存在的问题:: ^# I5 C9 e& a, U9 ]
我们也才开始vc学习,只是将自己了解的知识与和我们水平相当的新手们分享,希望一起提高。本程序有时不稳定,但音质很好,可能还有尚未暴露的错误,恳请广大高手们不吝赐教。E-mail: xuejing0103@126.comsmilewenjuan@yahoo.com.cn6 c- [; C; w8 a- b7 G0 {
% @5 R! }, O  C% P0 S
原文:http://www.vckbase.com/document/viewdoc/?id=1800
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|宁德市腾云网络科技有限公司 ( 闽ICP备2022007940号-5|闽公网安备 35092202000206号 )

GMT+8, 2026-6-18 10:27 , Processed in 0.020044 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表