找回密码
 注册
查看: 4730|回复: 0

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

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

, X1 `- {4 [/ v8 L# M7 t! Z' t5 v      下载源代码7 J. G. ^6 o$ i
        
7 f% o- x  m/ K) U# S; p        引言
/ ?' _2 o1 j/ Z- Z        我是C++的初学者,入门都要靠VCKBASE,好在里面有很多适合于初学者的例子,让我少走了很多弯路,为了回馈大家,我也把我最近刚完成的一个简单的小程序提供给大家,让那些曾经和我一样徘徊在C++大门之外的人能快些掌握要领,大家不妨看一看。- S; l1 n  f, j% G+ B
        本文以VC知识库第26期 栾义明 先生的《基于API的录音机程序》为基础的,在此深表感谢!相同之处不再重复,我在此基础上增加了将录音保存为wav文件的格式,便于大家参考。
% V* c! v* {7 s7 N基本步骤及思想:设定音频采集参数(采样率、声道等),打开音频设备、准备wave数据头和开辟缓存,操作采集的数据并保存为wav文件。设定音频回放参数,打开回放设备、准备wave数据头和写wave数据。另外样本程序需包含#include <mmsystem.h>和#pragmacomment(lib,"WINMM.LIB")多媒体支持。
9 _! P- X% V6 H; C, c4 d& I& w        在介绍程序前,需要你对wave文件的格式和相关一些基础概念有所了解,这些均可以在msdn中查找,为方便理解,我们将其整理,如果对这些基础知识已有所了解,可以跳过。
* j! Y" c+ k& _, n2 Z        
* y7 W7 i) c  A- ?      概念1、定义波形数据格式$ e9 H, ^# U8 q/ e1 k0 Y* o# g
      typedef struct{WORD  wFormatTag; / O3 {9 D  D* E  L
          WORD nChannels; # ~+ M( |+ d% D8 t3 c# |2 x
          DWORD nSamplesPerSec; $ t. k( _3 U  J$ e9 \/ W) _
          DWORD nAvgBytesPerSec;
. r5 m% C# k5 \% j2 s# s          WORD  nBlockAlign;
/ Z( D; Z! _0 _( u$ `1 h( h6 D7 @          WORD wBitsPerSample; 4 |# [- c  [& ]1 u& n
          WORD  cbSize; } WAVEFORMATEX;      具体参数解释如下:+ q7 r" q3 \3 X0 v) P
      wFormatTag:波形数据的格式,定义在MMREG.H文件中
  ~  B6 v# o8 |5 r" K7 w      nChannels:波形数据的通道数:单声道或立体声
$ m, D* v+ z3 D9 i# v% h      nSamplesPerSec:采样率,对于PCM格式的波形数据,采样率有8.0 kHz,11.025kHz,22.05 kHz,44.1 kHz等" P9 u8 A" u% G4 @7 D
      nAvgBytesPerSec:数据率,对于PCM格式的波形数据,数据率等于采样率乘以每样点字节数$ Y/ ~0 a4 H/ q+ {+ d. x/ @, y
      nBlockAlign:每个样点字节数
& H; r5 W+ R% u6 G5 h4 k- @" r5 s      wBitsPerSample:采样精度,对于PCM格式的波形数据,采样精度为8或16, {0 J; K$ r& u/ p2 S9 B
      cbSize:附加格式信息的数据块大小5 ^  |- A2 ]8 w" T. j- o4 Y
      概念2、定义设备头结构5 u0 ^7 ?3 ^2 N9 x8 j
    WAVEHDR定义了指向波形数据缓冲区的设备头。typedef struct { LPSTR lpData; 9 h  y/ |  W; `+ E* m; g7 P2 d8 k
        DWORD dwBufferLength;   h- s4 M" i5 J, z6 ^: E
        DWORD dwBytesRecorded; : S1 S8 Y( g' f) t% c& }
        DWORD dwUser;
4 Z, \9 A; H% y, |. n8 W$ `3 \- ^        DWORD dwFlags;
' U0 o* v, `/ {- }; }/ d0 ]        DWORD dwLoops;
9 c0 O" W4 ~" t; Q- r1 u2 x, I        struct wavehdr_tag * lpNext; 4 V% j/ U% B0 `8 k; j9 {
        DWORD reserved; } WAVEHDR;     lpData:波形数据的缓冲区地址
7 ?& L1 G  w' b2 R# `4 J5 y    dwBufferLength:波形数据的缓冲区地址的长度
3 C7 k. G- u) o7 C8 w2 |    dwBytesRecorded:当设备用于录音时,标志已经录入的数据长度
6 N* V! d  n; H+ I$ p* B    dwUser:用户数据
! @+ ^( m3 ?1 F2 ]( X  l* U: d    dwFlags:波形数据的缓冲区的属性1 Z/ I  t  N! K: R0 Z+ d# h
    dwLoops:播放循环的次数,仅用于播放控制中
  s4 }7 C" K3 J    lpNext和reserved均为保留值
' E. J4 p- }, a  K    注意:上述结构体以及我们在程序中所使用到的“HWAVEIN””HWAVEOUT”结构体均是系统已经存在的,我们只需要对其进行赋值即可。
. |! n* f7 \8 c* Q    概念3、消息处理函数
6 a2 y0 ?9 j  l' ~, ^+ A    MM_WIM_OPEN    //设备的打开
0 N1 Z; K( L+ D4 l: T3 `' t! G. Q    MM_WIM_DATA    //设备数据的采集及操作
: a, c" c! A# R# g! s) m    MM_WIM_CLOSE   //设备的关闭& I9 ~8 B4 E5 [% y4 ^
    相应回放设备的消息分别为MM_WOM_OPEN,MM_WOM_DATA,MM_WOM_CLOSE.+ X- E  N4 r" k( k
    注意:消息处理函数是消息自我驱动的,不需要我们的人为干预。比如:当我们打开设备时,系统会自动调用MM_WIM_OPEN,当我们将数据添加到缓冲区,而缓冲区满时,系统会自动调用MM_WIM_DATA,我们所需要做的,就是对该函数编好相应的源代码。2 o' g1 Q8 ]1 d0 x0 I0 W
    现在,我们进入正题:如何实现一个录音机。
) s! j: f; h% V0 l; `  q   
& A. q2 Q! p- B+ N( j    ⑴先对WAVEFORMATEX结构体进行赋值,然后为缓冲区分配内存pBuffer1=(PBYTE)malloc(INP_BUFFER_SIZE);' A  g9 I" k! k1 ?" o; I. `% m
pBuffer2=(PBYTE)malloc(INP_BUFFER_SIZE);
) q, H/ n6 L+ Z- p3 n对设备头结构体分配内存pWaveHdr1=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));
2 L- R0 Z$ b' i' I6 f2 ZpWaveHdr2=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));$ [: q6 f  W6 e) _( P  A# l  x& a# Q
然后使用wave音频相关函数对输入数据进行操作:
4 _2 `3 j, V( W! T" G6 ]0 F6 |) Z6 y1 @+ A
①为波形输入设备准备缓冲区waveInPrepareHeader(hWaveIn,pWaveHdr1,sizeof(WAVEHDR));
: \, a6 v' I  G# S* p! twaveInPrepareHeader(hWaveIn,pWaveHdr2,sizeof(WAVEHDR));% ]0 Y0 s4 g3 W+ Y
②为波形输入设备添加缓冲区waveInAddBuffer (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;
: }! X& @, w; w( s- I0 OwaveInAddBuffer (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;8 n, [& h2 `0 {
③启动声音输入设备,将输入数据写入内存waveInStart (hWaveIn) ;⑵编写消息处理函数,其中,MM_WIM_DATA函数是本程序的核心。其主要作用是将输入数据另行保存在一缓冲区内(pSaveBuffer),该缓冲区的长度将随着已录入数据的大小而增加,从而实现保存输入话音数据的功能。同时,可将缓冲区内数据保存为wav文件。其具体实现如下:CFile m_file;/ q3 t. k% H+ ^  p
CFileException fileException;! c4 e& O+ E: u
CString m_csFileName= "F:\\audio.wav";//保存路径
& f. l7 t6 ^6 W: K8 j9 u6 t6 ]. b/ Z1 pm_file.Open(m_csFileName,CFile::modeCreate|CFile::modeReadWrite, &fileException);
: A1 ?9 H4 M) w- S$ DDWORD m_WaveHeaderSize = 38;% J1 W: l0 m/ |; i1 L/ C; b
DWORD m_WaveFormatSize = 18;
1 ~+ ]" e! ~! @8 em_file.SeekToBegin();" \6 z9 }# j0 K: I9 T/ Y) y
m_file.Write("RIFF",4);
6 c7 N# E$ a3 z. S& Wunsigned int Sec=(sizeof pSaveBuffer + m_WaveHeaderSize);
2 b/ \' c; d. z5 u; \  @; \m_file.Write(&Sec,sizeof(Sec));+ v; L8 i( \9 k+ U3 {/ q
m_file.Write("WAVE",4);
, M, }$ p+ r* h0 im_file.Write("fmt ",4);  u# D* }& Y- }1 U! d; c
m_file.Write(&m_WaveFormatSize,sizeof(m_WaveFormatSize));
5 g/ q  }1 t" ^% |( y- x) A  Cm_file.Write(&waveform.wFormatTag,sizeof(waveform.wFormatTag));
0 h6 X; ~* E% i" s; fm_file.Write(&waveform.nChannels,sizeof(waveform.nChannels));
  g* ]. P0 A8 p& c: R2 H5 V2 Sm_file.Write(&waveform.nSamplesPerSec,sizeof(waveform.nSamplesPerSec));
+ \5 c( G% `* Z0 fm_file.Write(&waveform.nAvgBytesPerSec,sizeof(waveform.nAvgBytesPerSec));
% h$ V) [6 f) k; _$ h0 L) wm_file.Write(&waveform.nBlockAlign,sizeof(waveform.nBlockAlign));
* J; |- J+ i7 mm_file.Write(&waveform.wBitsPerSample,sizeof(waveform.wBitsPerSample));
1 `% H* T0 l( o) ], j: ~' W& Sm_file.Write(&waveform.cbSize,sizeof(waveform.cbSize));
6 q& I# j( z5 J4 D5 em_file.Write("data",4);: h0 N  V: U- a9 D! T6 a
m_file.Write(&dwDataLength,sizeof(dwDataLength));- P+ X& b0 V8 i3 L5 b( B
m_file.Write(pSaveBuffer,dwDataLength);
/ \# m( y7 z' K8 Em_file.Seek(dwDataLength,CFile::begin);+ z( k6 d$ H& b: C  l
m_file.Close();7 {$ Y1 Y1 V; O0 J. I3 L0 v
存在的问题:
+ E. Y% ?+ T! e, v+ O2 `. b  i& X我们也才开始vc学习,只是将自己了解的知识与和我们水平相当的新手们分享,希望一起提高。本程序有时不稳定,但音质很好,可能还有尚未暴露的错误,恳请广大高手们不吝赐教。E-mail: xuejing0103@126.com,smilewenjuan@yahoo.com.cn9 V- s' u/ ?9 c

0 B' s# z8 c: v原文:http://www.vckbase.com/document/viewdoc/?id=1800
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2026-10-2 02:24 , Processed in 0.015246 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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