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

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

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

' z# X% w8 u+ h0 T4 N6 F      下载源代码
  ~( d7 b' ?7 {/ S1 y7 L2 ^        
0 k) U7 ~% y$ v2 m0 ]        引言
7 Q4 t( F& B, b- I& L7 G. z5 `        我是C++的初学者,入门都要靠VCKBASE,好在里面有很多适合于初学者的例子,让我少走了很多弯路,为了回馈大家,我也把我最近刚完成的一个简单的小程序提供给大家,让那些曾经和我一样徘徊在C++大门之外的人能快些掌握要领,大家不妨看一看。" f4 _1 l6 D0 G! d: \/ x
        本文以VC知识库第26期 栾义明 先生的《基于API的录音机程序》为基础的,在此深表感谢!相同之处不再重复,我在此基础上增加了将录音保存为wav文件的格式,便于大家参考。! L% T; i& ?' d0 J  A
基本步骤及思想:设定音频采集参数(采样率、声道等),打开音频设备、准备wave数据头和开辟缓存,操作采集的数据并保存为wav文件。设定音频回放参数,打开回放设备、准备wave数据头和写wave数据。另外样本程序需包含#include <mmsystem.h>和#pragmacomment(lib,"WINMM.LIB")多媒体支持。
% v. S8 R  f( V) y) x& f7 e& c        在介绍程序前,需要你对wave文件的格式和相关一些基础概念有所了解,这些均可以在msdn中查找,为方便理解,我们将其整理,如果对这些基础知识已有所了解,可以跳过。: e0 K, X5 {' w! |: Q$ E2 s
        / H. i4 D9 {% c2 \3 c
      概念1、定义波形数据格式
8 {- @7 i1 |9 l5 a4 O8 H9 B      typedef struct{WORD  wFormatTag; $ r$ `1 B" c( H* V0 b4 T# t- l
          WORD nChannels;
2 x# G5 W0 A- L* p# p8 G, Z  ]          DWORD nSamplesPerSec; 6 h8 J7 G* T- K' S% X
          DWORD nAvgBytesPerSec;0 T% c+ E  C* M) M0 Q
          WORD  nBlockAlign; $ g& U/ `% ]+ p$ e; @5 G
          WORD wBitsPerSample;
/ j  q+ l! M1 T! Z/ `          WORD  cbSize; } WAVEFORMATEX;      具体参数解释如下:
* c( b3 E& k5 ~  g      wFormatTag:波形数据的格式,定义在MMREG.H文件中; d9 L3 o, J6 X3 I7 G+ C
      nChannels:波形数据的通道数:单声道或立体声4 X5 m5 D( B2 w7 {5 r2 ^9 S
      nSamplesPerSec:采样率,对于PCM格式的波形数据,采样率有8.0 kHz,11.025kHz,22.05 kHz,44.1 kHz等6 K. b4 L3 ~: K( C& b- e
      nAvgBytesPerSec:数据率,对于PCM格式的波形数据,数据率等于采样率乘以每样点字节数
! R& R, V" _7 ]) ~4 u" j; j0 h      nBlockAlign:每个样点字节数
9 l" R* U7 u$ ~* e+ P) H8 Y! p! H      wBitsPerSample:采样精度,对于PCM格式的波形数据,采样精度为8或16  l; {9 y& p+ Q) i( P( q
      cbSize:附加格式信息的数据块大小
' x# L( f# h' Z, b/ M' S5 o      概念2、定义设备头结构# L+ t3 u, M4 c/ `7 j9 ^
    WAVEHDR定义了指向波形数据缓冲区的设备头。typedef struct { LPSTR lpData;
0 g6 z' w& R* W$ a3 |9 I) y        DWORD dwBufferLength;
! z. R% ^" c! ~& C& e8 I' n3 _        DWORD dwBytesRecorded;
% u1 Z- a( w, i3 D+ k1 p+ S        DWORD dwUser; 6 I1 O$ _1 {) t3 r" C+ q: P
        DWORD dwFlags; 7 H( \  Y2 u4 U, B$ p' {
        DWORD dwLoops; # Q  K' N& s8 W& f
        struct wavehdr_tag * lpNext; 0 h) V/ E! W' E& B- H
        DWORD reserved; } WAVEHDR;     lpData:波形数据的缓冲区地址
( S8 Q$ I4 v& g0 X  ~    dwBufferLength:波形数据的缓冲区地址的长度6 B/ I# G4 F, P" R
    dwBytesRecorded:当设备用于录音时,标志已经录入的数据长度
/ |# B$ p' t# S9 U# J" @$ ?6 x! p. C$ y    dwUser:用户数据. b" H7 j# a' M' n9 O& V
    dwFlags:波形数据的缓冲区的属性# c$ k; t1 L+ u( I& A
    dwLoops:播放循环的次数,仅用于播放控制中+ ~; e4 I# h* _0 w* m
    lpNext和reserved均为保留值" N/ C+ E2 M- A  B
    注意:上述结构体以及我们在程序中所使用到的“HWAVEIN””HWAVEOUT”结构体均是系统已经存在的,我们只需要对其进行赋值即可。
0 O! o$ D7 `& I5 j* O    概念3、消息处理函数
) X7 B) z3 o4 S0 ^7 X( f; u( n    MM_WIM_OPEN    //设备的打开
  P' i1 |$ M2 S% F    MM_WIM_DATA    //设备数据的采集及操作
8 }' e! ^1 r: G# j" |: h7 E    MM_WIM_CLOSE   //设备的关闭4 Y2 d: H$ v9 \& R4 P5 O1 O( ?
    相应回放设备的消息分别为MM_WOM_OPEN,MM_WOM_DATA,MM_WOM_CLOSE.
; f( E1 c. V. C& g; [3 X# B    注意:消息处理函数是消息自我驱动的,不需要我们的人为干预。比如:当我们打开设备时,系统会自动调用MM_WIM_OPEN,当我们将数据添加到缓冲区,而缓冲区满时,系统会自动调用MM_WIM_DATA,我们所需要做的,就是对该函数编好相应的源代码。
, f) k6 J5 Z, q    现在,我们进入正题:如何实现一个录音机。
& r* c- s' ?) k  J9 _   
6 T" Y) @# ^( P    ⑴先对WAVEFORMATEX结构体进行赋值,然后为缓冲区分配内存pBuffer1=(PBYTE)malloc(INP_BUFFER_SIZE);
! p# W$ R5 R% V- TpBuffer2=(PBYTE)malloc(INP_BUFFER_SIZE);) ]( |4 m  x0 B1 b$ _4 e  I3 U! x
对设备头结构体分配内存pWaveHdr1=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));* @+ |+ e# Y% [* r  _( k
pWaveHdr2=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));; Q. F5 z. n) X7 \7 y6 f4 t
然后使用wave音频相关函数对输入数据进行操作:
# W$ r& m% n3 x9 S: Q( i
1 Y! q2 `4 r7 G! Z  Z①为波形输入设备准备缓冲区waveInPrepareHeader(hWaveIn,pWaveHdr1,sizeof(WAVEHDR));
( ^0 \: O! E+ N! L2 }" hwaveInPrepareHeader(hWaveIn,pWaveHdr2,sizeof(WAVEHDR));5 H. `* E0 l4 {4 N
②为波形输入设备添加缓冲区waveInAddBuffer (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;* g( O  d% v6 k6 Z  i7 f
waveInAddBuffer (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;
( h) e! G" k9 F! f③启动声音输入设备,将输入数据写入内存waveInStart (hWaveIn) ;⑵编写消息处理函数,其中,MM_WIM_DATA函数是本程序的核心。其主要作用是将输入数据另行保存在一缓冲区内(pSaveBuffer),该缓冲区的长度将随着已录入数据的大小而增加,从而实现保存输入话音数据的功能。同时,可将缓冲区内数据保存为wav文件。其具体实现如下:CFile m_file;8 w) p  o9 R1 i) c) \6 O
CFileException fileException;
) r, x/ M1 g2 z7 s# gCString m_csFileName= "F:\\audio.wav";//保存路径
& a7 v( ~, G* T: `+ q( k+ O$ g3 r/ tm_file.Open(m_csFileName,CFile::modeCreate|CFile::modeReadWrite, &fileException);
) s$ N# \) p  a5 g" ]- n! ~8 ODWORD m_WaveHeaderSize = 38;
- d3 J; p8 v7 x0 NDWORD m_WaveFormatSize = 18;
+ C" L" \6 |$ M0 m" Ym_file.SeekToBegin();" H3 @% n6 C3 A2 q* U5 \6 l( z
m_file.Write("RIFF",4);
. b2 H3 r7 @% k) V* {# Hunsigned int Sec=(sizeof pSaveBuffer + m_WaveHeaderSize);
9 ?5 p; l" J& O5 R$ ]m_file.Write(&Sec,sizeof(Sec));
) N) s6 Q3 c$ S& m2 km_file.Write("WAVE",4);( G* ~% G  Y2 M* N4 q/ ]
m_file.Write("fmt ",4);6 C  {( ?. C$ a4 T$ D1 u
m_file.Write(&m_WaveFormatSize,sizeof(m_WaveFormatSize));
3 c* z, M5 `4 B: I8 T& C: \m_file.Write(&waveform.wFormatTag,sizeof(waveform.wFormatTag));
! p& D: |7 F3 }; S" Fm_file.Write(&waveform.nChannels,sizeof(waveform.nChannels));
8 }! w& S+ r. _7 J8 o' o+ bm_file.Write(&waveform.nSamplesPerSec,sizeof(waveform.nSamplesPerSec));
1 ~5 O. {/ b+ A. d: N0 lm_file.Write(&waveform.nAvgBytesPerSec,sizeof(waveform.nAvgBytesPerSec));) D" ~" B4 @$ g) n: B1 f
m_file.Write(&waveform.nBlockAlign,sizeof(waveform.nBlockAlign));
( `! U3 K; h4 v+ g0 z" bm_file.Write(&waveform.wBitsPerSample,sizeof(waveform.wBitsPerSample));
, n, a! K+ C4 |3 Z  [6 |1 ~m_file.Write(&waveform.cbSize,sizeof(waveform.cbSize));" H- _/ d$ e. n1 `6 O
m_file.Write("data",4);: z: K! {7 q4 c& [+ D
m_file.Write(&dwDataLength,sizeof(dwDataLength));
- y; }3 ^7 N& mm_file.Write(pSaveBuffer,dwDataLength);
! @+ }) t9 L0 A4 y7 u1 E( vm_file.Seek(dwDataLength,CFile::begin);, X9 K7 B0 F, l1 h7 ?/ F# l- V) [
m_file.Close();6 E& S3 j( ?: O
存在的问题:& z, P. S: P! D1 i' Q, v: o
我们也才开始vc学习,只是将自己了解的知识与和我们水平相当的新手们分享,希望一起提高。本程序有时不稳定,但音质很好,可能还有尚未暴露的错误,恳请广大高手们不吝赐教。E-mail: xuejing0103@126.com,smilewenjuan@yahoo.com.cn; w7 ?: x' b2 b. l  E
) G3 r8 H/ ]" Q/ ~) t- L. V! [
原文:http://www.vckbase.com/document/viewdoc/?id=1800
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2026-10-1 23:12 , Processed in 0.017813 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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