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

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

[复制链接]
发表于 2007-11-30 13:43:24 | 显示全部楼层 |阅读模式
作者:任雪景、文娟
# l' a7 b' {% ?& I
      下载源代码
7 O9 U$ w0 m: n9 @        
% y3 `# l  {6 b: V, F8 ^        引言3 ^: l3 @8 W; l' x$ G
        我是C++的初学者,入门都要靠VCKBASE,好在里面有很多适合于初学者的例子,让我少走了很多弯路,为了回馈大家,我也把我最近刚完成的一个简单的小程序提供给大家,让那些曾经和我一样徘徊在C++大门之外的人能快些掌握要领,大家不妨看一看。8 G) K, \% F% q" R$ b
        本文以VC知识库第26期 栾义明 先生的《基于API的录音机程序》为基础的,在此深表感谢!相同之处不再重复,我在此基础上增加了将录音保存为wav文件的格式,便于大家参考。" h. K% a# X5 j  |* @9 G% S- G/ m5 M
基本步骤及思想:设定音频采集参数(采样率、声道等),打开音频设备、准备wave数据头和开辟缓存,操作采集的数据并保存为wav文件。设定音频回放参数,打开回放设备、准备wave数据头和写wave数据。另外样本程序需包含#include <mmsystem.h>和#pragmacomment(lib,"WINMM.LIB")多媒体支持。' Q& V3 n7 W; w4 D
        在介绍程序前,需要你对wave文件的格式和相关一些基础概念有所了解,这些均可以在msdn中查找,为方便理解,我们将其整理,如果对这些基础知识已有所了解,可以跳过。/ x" x( }+ g2 ~* ]- g+ p" x2 {
        
3 y: C7 Q9 J& V4 M7 z! L1 {      概念1、定义波形数据格式2 L: x2 c" Q; R1 u2 ^
      typedef struct{WORD  wFormatTag;
: {% k- C4 C' ?- ^7 H          WORD nChannels;
( u6 N( ~+ c$ ^% G3 t+ a          DWORD nSamplesPerSec; " X  h- g( {% ?3 L9 Y! b# t" j
          DWORD nAvgBytesPerSec;
* P2 h% J/ q! ^# e( _  Y          WORD  nBlockAlign;
3 |, _# M$ W; z0 W2 J. g$ m          WORD wBitsPerSample; 8 r* r9 K8 A# ]; C$ H1 F/ n3 \
          WORD  cbSize; } WAVEFORMATEX;      具体参数解释如下:
6 _- ]8 f5 C+ j0 D      wFormatTag:波形数据的格式,定义在MMREG.H文件中; F; {) I9 {& N7 |- K1 h" A
      nChannels:波形数据的通道数:单声道或立体声
" X* f) f$ |" C+ D) D- ^& ]      nSamplesPerSec:采样率,对于PCM格式的波形数据,采样率有8.0 kHz,11.025kHz,22.05 kHz,44.1 kHz等' C5 k& T( y8 k; J
      nAvgBytesPerSec:数据率,对于PCM格式的波形数据,数据率等于采样率乘以每样点字节数
8 o; m* V+ f$ R5 y      nBlockAlign:每个样点字节数
, \- t- X4 v3 d) d, t      wBitsPerSample:采样精度,对于PCM格式的波形数据,采样精度为8或161 i  r4 v1 j/ n6 h/ `  Z
      cbSize:附加格式信息的数据块大小2 a9 u$ N9 y2 r# B9 L: l3 L8 g
      概念2、定义设备头结构
  z0 B) j- G. H% @( N% d, Q1 f8 ~1 ?    WAVEHDR定义了指向波形数据缓冲区的设备头。typedef struct { LPSTR lpData;
, ^: b' \' p6 V, R* \7 ^& N        DWORD dwBufferLength; 9 }9 q, W$ f0 l  q
        DWORD dwBytesRecorded; - c7 h) X/ ?2 p' I: [; s9 _
        DWORD dwUser; 8 X: q. x3 j. J$ D4 |
        DWORD dwFlags;
$ i3 R) j4 X7 A; }        DWORD dwLoops; % K* |& x' x9 _
        struct wavehdr_tag * lpNext;
4 {! H3 y" y8 L( \        DWORD reserved; } WAVEHDR;     lpData:波形数据的缓冲区地址  ^1 ^6 Y" e# w3 T0 P  N, z$ p
    dwBufferLength:波形数据的缓冲区地址的长度* z3 ^$ ~* A7 h
    dwBytesRecorded:当设备用于录音时,标志已经录入的数据长度5 y% o4 r# i1 ^0 @7 A  S
    dwUser:用户数据! |, H( _; M  v3 L( x
    dwFlags:波形数据的缓冲区的属性
6 j& G1 [5 [/ H& ]% j- r9 t' A7 n    dwLoops:播放循环的次数,仅用于播放控制中
2 }& I. ?& W/ b7 o    lpNext和reserved均为保留值1 W# I1 }( s. H6 s0 m6 K9 l
    注意:上述结构体以及我们在程序中所使用到的“HWAVEIN””HWAVEOUT”结构体均是系统已经存在的,我们只需要对其进行赋值即可。# C( w  x* k' V2 T
    概念3、消息处理函数% M9 @  k/ I- _: c8 c- R6 s1 q. b
    MM_WIM_OPEN    //设备的打开- c: K, [% t  f* t
    MM_WIM_DATA    //设备数据的采集及操作
; S$ w: r  q' S& u! c    MM_WIM_CLOSE   //设备的关闭
  `: u2 {4 T! c8 B! K0 m    相应回放设备的消息分别为MM_WOM_OPEN,MM_WOM_DATA,MM_WOM_CLOSE.1 \  M' t+ U+ E( @
    注意:消息处理函数是消息自我驱动的,不需要我们的人为干预。比如:当我们打开设备时,系统会自动调用MM_WIM_OPEN,当我们将数据添加到缓冲区,而缓冲区满时,系统会自动调用MM_WIM_DATA,我们所需要做的,就是对该函数编好相应的源代码。3 }' ?3 N# H2 v! o3 C
    现在,我们进入正题:如何实现一个录音机。( j$ _# T, F) p* B. N
    8 a$ R* u% u9 D5 p. d' D! S$ D) c( e
    ⑴先对WAVEFORMATEX结构体进行赋值,然后为缓冲区分配内存pBuffer1=(PBYTE)malloc(INP_BUFFER_SIZE);, W' J, @, C) \! D; F3 E
pBuffer2=(PBYTE)malloc(INP_BUFFER_SIZE);3 q: s! y4 ?+ e' Z! |
对设备头结构体分配内存pWaveHdr1=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));, Y4 r/ l+ k8 h! n" a, P0 l9 b) G  ?
pWaveHdr2=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));# M3 Y- l# Y7 h9 m5 h! S6 Q/ s7 t
然后使用wave音频相关函数对输入数据进行操作:  y) t* @( s2 }# p* D# q

! ~$ B! k* K' ]2 r! x% t①为波形输入设备准备缓冲区waveInPrepareHeader(hWaveIn,pWaveHdr1,sizeof(WAVEHDR));/ X) p8 v: L& j: W$ X! b# k& q8 O. r$ @
waveInPrepareHeader(hWaveIn,pWaveHdr2,sizeof(WAVEHDR));
/ X* t9 E/ x1 X1 ^, `4 Q②为波形输入设备添加缓冲区waveInAddBuffer (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;: R# ~4 ]% A( I3 M4 t3 n7 |
waveInAddBuffer (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;6 V2 _, j+ ^0 l. [2 v+ [( [9 A
③启动声音输入设备,将输入数据写入内存waveInStart (hWaveIn) ;⑵编写消息处理函数,其中,MM_WIM_DATA函数是本程序的核心。其主要作用是将输入数据另行保存在一缓冲区内(pSaveBuffer),该缓冲区的长度将随着已录入数据的大小而增加,从而实现保存输入话音数据的功能。同时,可将缓冲区内数据保存为wav文件。其具体实现如下:CFile m_file;
7 S* a, }# [1 j) L/ tCFileException fileException;
* y% _3 s, _" N7 E+ s2 aCString m_csFileName= "F:\\audio.wav";//保存路径
- v0 g  e. t' Y& Hm_file.Open(m_csFileName,CFile::modeCreate|CFile::modeReadWrite, &fileException);4 R: z. M" R3 M$ n( q; F* u
DWORD m_WaveHeaderSize = 38;
% W# t& o9 F# L+ ]5 c% ^DWORD m_WaveFormatSize = 18;
% [8 i) q$ `) U2 I) M0 x& Dm_file.SeekToBegin();
8 t  \/ [9 L6 E" J3 b/ Am_file.Write("RIFF",4);" m; }) t, r  e. k" K" [6 B7 k
unsigned int Sec=(sizeof pSaveBuffer + m_WaveHeaderSize);- v+ y) k- Y$ z. b2 X2 C2 k) m
m_file.Write(&Sec,sizeof(Sec));
4 e1 z  K/ K1 A1 im_file.Write("WAVE",4);5 V/ ]5 C. A& M) k2 t
m_file.Write("fmt ",4);' d/ f6 J9 R: C3 V7 O0 f- [0 g  R
m_file.Write(&m_WaveFormatSize,sizeof(m_WaveFormatSize));7 Q$ S* X; K% e2 g
m_file.Write(&waveform.wFormatTag,sizeof(waveform.wFormatTag));
7 |$ o( V  G" K% z+ H% ?+ z2 Pm_file.Write(&waveform.nChannels,sizeof(waveform.nChannels));
7 B: S2 J% R9 r, _! Hm_file.Write(&waveform.nSamplesPerSec,sizeof(waveform.nSamplesPerSec));$ I! m" s# W6 H: J
m_file.Write(&waveform.nAvgBytesPerSec,sizeof(waveform.nAvgBytesPerSec));
; ?/ G5 W1 y0 R1 \7 |* l% Y* Fm_file.Write(&waveform.nBlockAlign,sizeof(waveform.nBlockAlign));
* ^4 S$ {" F. Lm_file.Write(&waveform.wBitsPerSample,sizeof(waveform.wBitsPerSample));+ w2 M1 G: b  B
m_file.Write(&waveform.cbSize,sizeof(waveform.cbSize));
, ~4 y7 S( {4 J. pm_file.Write("data",4);  u/ p/ x: z0 _" b
m_file.Write(&dwDataLength,sizeof(dwDataLength));
5 I7 g3 x1 q' x4 l& |m_file.Write(pSaveBuffer,dwDataLength);
; {4 i7 i6 ]' {/ C6 Cm_file.Seek(dwDataLength,CFile::begin);
$ e0 a, k: U% P+ @, n0 w! xm_file.Close();- t  b4 P& }) U0 D2 [, |
存在的问题:
+ _8 g0 M9 O6 }: L我们也才开始vc学习,只是将自己了解的知识与和我们水平相当的新手们分享,希望一起提高。本程序有时不稳定,但音质很好,可能还有尚未暴露的错误,恳请广大高手们不吝赐教。E-mail: xuejing0103@126.comsmilewenjuan@yahoo.com.cn2 u6 t2 \. n" X$ S: A2 b0 A
, e) E! p* d8 X& t
原文:http://www.vckbase.com/document/viewdoc/?id=1800
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2026-5-2 08:56 , Processed in 0.019275 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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