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

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

[复制链接]
发表于 2007-11-30 13:43:24 | 显示全部楼层 |阅读模式
作者:任雪景、文娟
, z0 C4 t+ X, @4 y# P! s
      下载源代码
; Z" U7 K5 i: L& ?3 H# Z$ u5 L        & F4 R/ V: U$ c% Y8 ^1 j: c9 c& q. R
        引言0 {) K+ r6 e6 ^
        我是C++的初学者,入门都要靠VCKBASE,好在里面有很多适合于初学者的例子,让我少走了很多弯路,为了回馈大家,我也把我最近刚完成的一个简单的小程序提供给大家,让那些曾经和我一样徘徊在C++大门之外的人能快些掌握要领,大家不妨看一看。% \3 w( V0 I; V' B% ?  T
        本文以VC知识库第26期 栾义明 先生的《基于API的录音机程序》为基础的,在此深表感谢!相同之处不再重复,我在此基础上增加了将录音保存为wav文件的格式,便于大家参考。  Z, L: T' ~* K
基本步骤及思想:设定音频采集参数(采样率、声道等),打开音频设备、准备wave数据头和开辟缓存,操作采集的数据并保存为wav文件。设定音频回放参数,打开回放设备、准备wave数据头和写wave数据。另外样本程序需包含#include <mmsystem.h>和#pragmacomment(lib,"WINMM.LIB")多媒体支持。$ ~* q$ h) @" j- g1 a
        在介绍程序前,需要你对wave文件的格式和相关一些基础概念有所了解,这些均可以在msdn中查找,为方便理解,我们将其整理,如果对这些基础知识已有所了解,可以跳过。# a7 n  V/ C9 r' D: h: U
        
2 W! @; G2 _# o  t) d1 `' q5 |+ D      概念1、定义波形数据格式
4 w" \: ~0 y( r0 e1 T      typedef struct{WORD  wFormatTag;
  X* s7 e" d$ p0 }' j  ^          WORD nChannels;
* k2 L' J3 l( D; V0 s( o          DWORD nSamplesPerSec;
( s/ [5 `8 F$ W0 R& _6 \          DWORD nAvgBytesPerSec;: \# a- ]% G# ^/ R3 M
          WORD  nBlockAlign;
! L1 j$ z" `, @% p; n          WORD wBitsPerSample; - l# U2 o6 b" S$ _* N0 G. t
          WORD  cbSize; } WAVEFORMATEX;      具体参数解释如下:
9 @3 f6 I4 l9 v. |" d& c. c5 B      wFormatTag:波形数据的格式,定义在MMREG.H文件中# B2 D, F7 T: H& Z+ [# M) s
      nChannels:波形数据的通道数:单声道或立体声& u5 G: i3 R& w7 U, _
      nSamplesPerSec:采样率,对于PCM格式的波形数据,采样率有8.0 kHz,11.025kHz,22.05 kHz,44.1 kHz等
0 H; F& ~4 H% @& X- i* N      nAvgBytesPerSec:数据率,对于PCM格式的波形数据,数据率等于采样率乘以每样点字节数! ]2 \& X+ m  m
      nBlockAlign:每个样点字节数* R7 @3 o( [; \% R7 }
      wBitsPerSample:采样精度,对于PCM格式的波形数据,采样精度为8或16
7 H$ G# ^: y4 C! K      cbSize:附加格式信息的数据块大小
% `/ t* a7 [$ y- H) K      概念2、定义设备头结构
6 T1 f5 `3 s$ T2 W/ @7 X4 c% f    WAVEHDR定义了指向波形数据缓冲区的设备头。typedef struct { LPSTR lpData;
' Z9 I! v1 @% Y( [2 G5 j        DWORD dwBufferLength; 0 E# m# Y1 J6 f# V6 a* {
        DWORD dwBytesRecorded;
% @( Z1 }1 J) W% F! Y/ I        DWORD dwUser; # H& I/ W# S' g' a% K2 D
        DWORD dwFlags;
: b: ^# ]5 j( w6 h  c' k        DWORD dwLoops; ( T9 N1 l2 W3 |/ X
        struct wavehdr_tag * lpNext; ! \2 J% T7 m" u2 |, j1 d: V
        DWORD reserved; } WAVEHDR;     lpData:波形数据的缓冲区地址. q) ^+ s& s1 {
    dwBufferLength:波形数据的缓冲区地址的长度
0 @/ K' \; m, e/ g# e+ ?    dwBytesRecorded:当设备用于录音时,标志已经录入的数据长度
+ j# c7 {8 I5 b3 T0 L+ Q    dwUser:用户数据
2 a8 }' M5 e' N8 m: Q    dwFlags:波形数据的缓冲区的属性
9 j! b* E* [% W6 g$ n! r  H8 B    dwLoops:播放循环的次数,仅用于播放控制中
; m1 L4 ?9 _* X; Y+ t% q    lpNext和reserved均为保留值' X) i4 D- `! P  E- A5 O
    注意:上述结构体以及我们在程序中所使用到的“HWAVEIN””HWAVEOUT”结构体均是系统已经存在的,我们只需要对其进行赋值即可。# r, d7 N( t/ o; O# ^9 w
    概念3、消息处理函数
7 `$ n) d/ w: ]; ]  y! p! {/ m    MM_WIM_OPEN    //设备的打开& Q- H4 Z6 N" Z& D! w3 w  l
    MM_WIM_DATA    //设备数据的采集及操作
# f2 s- q+ d1 |- a0 c6 i  Q" n7 j    MM_WIM_CLOSE   //设备的关闭
7 O0 p$ F+ Y, j9 ^$ L) U: Q$ v* I    相应回放设备的消息分别为MM_WOM_OPEN,MM_WOM_DATA,MM_WOM_CLOSE.! }" p, j8 P" m7 x+ Z
    注意:消息处理函数是消息自我驱动的,不需要我们的人为干预。比如:当我们打开设备时,系统会自动调用MM_WIM_OPEN,当我们将数据添加到缓冲区,而缓冲区满时,系统会自动调用MM_WIM_DATA,我们所需要做的,就是对该函数编好相应的源代码。
7 K# l" L7 \- B/ _% V! S1 O    现在,我们进入正题:如何实现一个录音机。0 [9 u9 n; @# J( e& G1 d3 }
    ! \9 b) f6 v& L
    ⑴先对WAVEFORMATEX结构体进行赋值,然后为缓冲区分配内存pBuffer1=(PBYTE)malloc(INP_BUFFER_SIZE);% E9 Z, R& i1 B" o/ E) O$ ^8 i5 T
pBuffer2=(PBYTE)malloc(INP_BUFFER_SIZE);
$ D" |4 I; U% G9 T5 ], ^* i/ H对设备头结构体分配内存pWaveHdr1=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));
; l/ F0 V, U- X$ xpWaveHdr2=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));
" J; W5 a4 {0 |! _5 }然后使用wave音频相关函数对输入数据进行操作:
$ c3 D6 i4 a1 M7 L
9 g$ F: a) M% {! G& |①为波形输入设备准备缓冲区waveInPrepareHeader(hWaveIn,pWaveHdr1,sizeof(WAVEHDR));
; m& O3 H* u7 h+ p. K0 ZwaveInPrepareHeader(hWaveIn,pWaveHdr2,sizeof(WAVEHDR));
- F: |# W7 J- @& V& Y+ A②为波形输入设备添加缓冲区waveInAddBuffer (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;
! O8 {& g% U( d$ E' l' S; NwaveInAddBuffer (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;
- J! Y7 Y: B9 s* ?2 A5 |③启动声音输入设备,将输入数据写入内存waveInStart (hWaveIn) ;⑵编写消息处理函数,其中,MM_WIM_DATA函数是本程序的核心。其主要作用是将输入数据另行保存在一缓冲区内(pSaveBuffer),该缓冲区的长度将随着已录入数据的大小而增加,从而实现保存输入话音数据的功能。同时,可将缓冲区内数据保存为wav文件。其具体实现如下:CFile m_file;
9 `  s- X. X2 K# O5 C/ m+ U  TCFileException fileException;) B, L. l, O$ x& J
CString m_csFileName= "F:\\audio.wav";//保存路径
0 x. K: x1 q8 N: m& n3 C; s* ~5 Sm_file.Open(m_csFileName,CFile::modeCreate|CFile::modeReadWrite, &fileException);0 @) T- S6 g8 s" V
DWORD m_WaveHeaderSize = 38;7 p5 q" Z% y/ U
DWORD m_WaveFormatSize = 18;
: r; _$ u- B. l/ |8 K6 Sm_file.SeekToBegin();
. C; T$ J7 ^6 E4 rm_file.Write("RIFF",4);# v3 P6 r4 W' F7 U
unsigned int Sec=(sizeof pSaveBuffer + m_WaveHeaderSize);
. e7 u) i0 w8 R' pm_file.Write(&Sec,sizeof(Sec));
$ A. `; C7 a1 v/ B% D. Fm_file.Write("WAVE",4);3 P6 a7 e1 v/ K# g3 p, X
m_file.Write("fmt ",4);- w( E; G/ ^2 `9 y+ b) i% o
m_file.Write(&m_WaveFormatSize,sizeof(m_WaveFormatSize));) m' {  M$ x0 R, N$ Y1 N: h- B
m_file.Write(&waveform.wFormatTag,sizeof(waveform.wFormatTag));% X) X& W- ]. U/ O* p' O, u- s
m_file.Write(&waveform.nChannels,sizeof(waveform.nChannels));
! |9 h) Q4 n  ]( y0 f( \& Sm_file.Write(&waveform.nSamplesPerSec,sizeof(waveform.nSamplesPerSec));5 D. Q, |% w( U
m_file.Write(&waveform.nAvgBytesPerSec,sizeof(waveform.nAvgBytesPerSec));: L' H9 I' V7 A0 V2 M# h$ l* k
m_file.Write(&waveform.nBlockAlign,sizeof(waveform.nBlockAlign));& q/ e! l) {' n- U7 H! r
m_file.Write(&waveform.wBitsPerSample,sizeof(waveform.wBitsPerSample));
0 G) ~, }. q: Y+ j2 {6 sm_file.Write(&waveform.cbSize,sizeof(waveform.cbSize));$ k1 F8 e( Q8 v; a
m_file.Write("data",4);6 j4 m8 R+ }1 D8 u. t
m_file.Write(&dwDataLength,sizeof(dwDataLength));
% H' c/ A; Q, V' c  E- U5 Pm_file.Write(pSaveBuffer,dwDataLength);
1 R& \8 n. z/ {% r1 O1 [m_file.Seek(dwDataLength,CFile::begin);
5 C# j' y( I/ y/ v& Z4 gm_file.Close();8 P4 C6 K% A$ Y$ l2 C7 a
存在的问题:+ b& f& o1 q" [- C6 x$ ]( @. M
我们也才开始vc学习,只是将自己了解的知识与和我们水平相当的新手们分享,希望一起提高。本程序有时不稳定,但音质很好,可能还有尚未暴露的错误,恳请广大高手们不吝赐教。E-mail: xuejing0103@126.comsmilewenjuan@yahoo.com.cn. z( i( \4 ~) E0 w0 F

+ D3 K4 U1 J% Z6 l- Q  G4 ]( m原文:http://www.vckbase.com/document/viewdoc/?id=1800
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2026-5-2 11:47 , Processed in 0.019368 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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