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

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

[复制链接]
发表于 2007-11-30 13:43:24 | 显示全部楼层 |阅读模式
作者:任雪景、文娟
+ X0 y1 X6 H2 ~4 \, q
      下载源代码
  w( Z# @1 \" A3 X' |# d7 M        
7 O, h# f: N0 o7 V* F( o        引言
1 C- n: n+ W& Z5 B& u; \. C        我是C++的初学者,入门都要靠VCKBASE,好在里面有很多适合于初学者的例子,让我少走了很多弯路,为了回馈大家,我也把我最近刚完成的一个简单的小程序提供给大家,让那些曾经和我一样徘徊在C++大门之外的人能快些掌握要领,大家不妨看一看。
1 C5 f. e9 n+ R        本文以VC知识库第26期 栾义明 先生的《基于API的录音机程序》为基础的,在此深表感谢!相同之处不再重复,我在此基础上增加了将录音保存为wav文件的格式,便于大家参考。% I* |. v# ?$ Q- y  S
基本步骤及思想:设定音频采集参数(采样率、声道等),打开音频设备、准备wave数据头和开辟缓存,操作采集的数据并保存为wav文件。设定音频回放参数,打开回放设备、准备wave数据头和写wave数据。另外样本程序需包含#include <mmsystem.h>和#pragmacomment(lib,"WINMM.LIB")多媒体支持。
/ T& R2 m0 m  r; T) ^$ ~. P        在介绍程序前,需要你对wave文件的格式和相关一些基础概念有所了解,这些均可以在msdn中查找,为方便理解,我们将其整理,如果对这些基础知识已有所了解,可以跳过。: Q! y8 j/ Z$ U: w$ G. W& T
        " ]$ p6 @3 `8 ~; E$ }
      概念1、定义波形数据格式
" e8 o+ U/ B4 A' q: ?, O4 n5 u      typedef struct{WORD  wFormatTag;
4 y2 L/ j: K+ d3 z          WORD nChannels; + \8 y" _0 m- Z- c
          DWORD nSamplesPerSec; 6 c7 Z% y( z- Z" P9 Y4 L
          DWORD nAvgBytesPerSec;  a, Z0 a2 V: b( k
          WORD  nBlockAlign; ; }7 S2 r1 s: ?# r; ~
          WORD wBitsPerSample;
4 q6 W, v& W  l  K# Y2 {" E+ `+ K- m          WORD  cbSize; } WAVEFORMATEX;      具体参数解释如下:/ {$ W  p. \0 I
      wFormatTag:波形数据的格式,定义在MMREG.H文件中# D) T+ y2 T! r9 u+ }, ~
      nChannels:波形数据的通道数:单声道或立体声
% T2 D1 g0 ~4 F5 B      nSamplesPerSec:采样率,对于PCM格式的波形数据,采样率有8.0 kHz,11.025kHz,22.05 kHz,44.1 kHz等
! S3 Y  A8 l' m/ f8 A      nAvgBytesPerSec:数据率,对于PCM格式的波形数据,数据率等于采样率乘以每样点字节数  X% p! S5 Y% j% O' Q
      nBlockAlign:每个样点字节数$ A+ k9 g4 F9 @' W
      wBitsPerSample:采样精度,对于PCM格式的波形数据,采样精度为8或16
" {$ Y0 g- j5 ]3 \) s# I+ |, q      cbSize:附加格式信息的数据块大小
& H  K: A* C6 Q7 j1 Z      概念2、定义设备头结构
! z+ W4 l5 U' |: V5 ^    WAVEHDR定义了指向波形数据缓冲区的设备头。typedef struct { LPSTR lpData;
+ R+ M4 w" S; W% j        DWORD dwBufferLength;
- g+ t# {& k6 L% u! n* I        DWORD dwBytesRecorded;
) {$ Z( J. Q' |" f8 N9 W+ |: g" \        DWORD dwUser;
+ y& R% r9 T/ J) [        DWORD dwFlags;
* ?4 s0 R7 c5 X. q; o; Z        DWORD dwLoops;
& t2 I4 F6 N5 H        struct wavehdr_tag * lpNext; ) R1 E5 N# S& N- R! Z
        DWORD reserved; } WAVEHDR;     lpData:波形数据的缓冲区地址: H) O. V! l. W& _
    dwBufferLength:波形数据的缓冲区地址的长度
8 G) ]& }  E9 d' r8 T  J    dwBytesRecorded:当设备用于录音时,标志已经录入的数据长度
& H2 J7 _/ C. ~; i' Z+ I, S/ M    dwUser:用户数据& C' J3 o- l: o; P4 |6 S
    dwFlags:波形数据的缓冲区的属性
- ?3 z' L/ _4 x' S; Y3 k, p, K    dwLoops:播放循环的次数,仅用于播放控制中
6 J+ i- a1 d% |  s( }- ?- j2 a$ T    lpNext和reserved均为保留值
; [& N5 U; m0 }7 q    注意:上述结构体以及我们在程序中所使用到的“HWAVEIN””HWAVEOUT”结构体均是系统已经存在的,我们只需要对其进行赋值即可。
6 f9 U3 x6 @: x' O3 m( T6 x    概念3、消息处理函数/ F' W$ q6 Q3 h, S
    MM_WIM_OPEN    //设备的打开
1 C! N" A! S' r, Y/ |    MM_WIM_DATA    //设备数据的采集及操作0 w/ Z7 p; E- c7 v& q% w7 U7 E9 N
    MM_WIM_CLOSE   //设备的关闭& O: H5 e8 [( ~. l
    相应回放设备的消息分别为MM_WOM_OPEN,MM_WOM_DATA,MM_WOM_CLOSE.2 J7 A: C6 F* H1 f9 E% |
    注意:消息处理函数是消息自我驱动的,不需要我们的人为干预。比如:当我们打开设备时,系统会自动调用MM_WIM_OPEN,当我们将数据添加到缓冲区,而缓冲区满时,系统会自动调用MM_WIM_DATA,我们所需要做的,就是对该函数编好相应的源代码。
! b- }0 b) t8 V( e3 _, ~, _' s    现在,我们进入正题:如何实现一个录音机。
6 c8 Z: n5 {9 [! t5 y+ O; c   
8 t; P" \5 O3 S& m- s5 c2 J    ⑴先对WAVEFORMATEX结构体进行赋值,然后为缓冲区分配内存pBuffer1=(PBYTE)malloc(INP_BUFFER_SIZE);
0 J/ A" e1 U- p/ p+ P) m* hpBuffer2=(PBYTE)malloc(INP_BUFFER_SIZE);
  f8 R9 Z" J$ L) R7 h0 k对设备头结构体分配内存pWaveHdr1=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));
& V4 I% _' x. _5 z/ u; x% XpWaveHdr2=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));
/ Z# U; P5 L  k9 c4 l$ p然后使用wave音频相关函数对输入数据进行操作:
5 y( z2 G+ R, w1 k5 H0 V% \0 R2 h) w$ Y! U
①为波形输入设备准备缓冲区waveInPrepareHeader(hWaveIn,pWaveHdr1,sizeof(WAVEHDR));- t; \1 J6 m: K8 \2 b4 Q% s$ e
waveInPrepareHeader(hWaveIn,pWaveHdr2,sizeof(WAVEHDR));
( ?8 j  L1 c7 m( T( u* u5 h1 r! h②为波形输入设备添加缓冲区waveInAddBuffer (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;
) }4 m! C9 q# i* P8 ^waveInAddBuffer (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;& M0 W. X9 ?# @- K: i
③启动声音输入设备,将输入数据写入内存waveInStart (hWaveIn) ;⑵编写消息处理函数,其中,MM_WIM_DATA函数是本程序的核心。其主要作用是将输入数据另行保存在一缓冲区内(pSaveBuffer),该缓冲区的长度将随着已录入数据的大小而增加,从而实现保存输入话音数据的功能。同时,可将缓冲区内数据保存为wav文件。其具体实现如下:CFile m_file;
* ?4 g1 d5 l" |. MCFileException fileException;* ^. E* P& C: H: e( [
CString m_csFileName= "F:\\audio.wav";//保存路径
5 E0 R8 l$ b, B0 }$ Y$ i! k. Y7 @- @! {m_file.Open(m_csFileName,CFile::modeCreate|CFile::modeReadWrite, &fileException);* _. X8 C$ f3 `0 O" j9 e; D
DWORD m_WaveHeaderSize = 38;7 \0 F5 ^6 z: o( u
DWORD m_WaveFormatSize = 18;5 j- f! L: V7 y3 k  |; A/ S
m_file.SeekToBegin();4 w. W+ g' b; L# a
m_file.Write("RIFF",4);  _9 C  F, n$ `: _, i
unsigned int Sec=(sizeof pSaveBuffer + m_WaveHeaderSize);7 _, M8 \* w& N- O7 c
m_file.Write(&Sec,sizeof(Sec));
" r3 D4 w6 i) y, [# f% G& wm_file.Write("WAVE",4);# d( W' Q$ y/ ]: O# N
m_file.Write("fmt ",4);+ }# `( @- y5 o, r- o. z
m_file.Write(&m_WaveFormatSize,sizeof(m_WaveFormatSize));1 T0 S* N* t5 a( `! M( l4 t% B: g
m_file.Write(&waveform.wFormatTag,sizeof(waveform.wFormatTag));
, A+ Y% I7 i- @( _# L! W) Nm_file.Write(&waveform.nChannels,sizeof(waveform.nChannels));. S8 G" d7 O' J& B0 y* i0 U
m_file.Write(&waveform.nSamplesPerSec,sizeof(waveform.nSamplesPerSec));
) _5 @, F$ A% P& t) G. v7 pm_file.Write(&waveform.nAvgBytesPerSec,sizeof(waveform.nAvgBytesPerSec));
2 i& n9 v' J0 |% t' ^: ~m_file.Write(&waveform.nBlockAlign,sizeof(waveform.nBlockAlign));3 g4 C6 @9 y1 R. U$ _3 S0 C) x
m_file.Write(&waveform.wBitsPerSample,sizeof(waveform.wBitsPerSample));- ?. C9 I( p" J& e
m_file.Write(&waveform.cbSize,sizeof(waveform.cbSize));
, w0 R+ a+ f! o' W! h$ mm_file.Write("data",4);$ ^5 W/ P- ]) S" G. h
m_file.Write(&dwDataLength,sizeof(dwDataLength));+ Q" r. N) C: W7 C5 Y
m_file.Write(pSaveBuffer,dwDataLength);3 h* s6 B  b# ]9 `" O
m_file.Seek(dwDataLength,CFile::begin);9 l9 p1 S0 O  O
m_file.Close();
# k7 ?" A6 X9 h7 \存在的问题:
' y" w; t( b6 P$ v% j) K我们也才开始vc学习,只是将自己了解的知识与和我们水平相当的新手们分享,希望一起提高。本程序有时不稳定,但音质很好,可能还有尚未暴露的错误,恳请广大高手们不吝赐教。E-mail: xuejing0103@126.comsmilewenjuan@yahoo.com.cn, J& D& Y# V6 |7 f$ H) L. ?& q: }+ |

+ i5 O+ b2 G3 K3 k- x4 U* {' l1 }) d原文:http://www.vckbase.com/document/viewdoc/?id=1800
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2025-6-19 11:57 , Processed in 0.014705 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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