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

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

[复制链接]
发表于 2007-11-30 13:43:24 | 显示全部楼层 |阅读模式
作者:任雪景、文娟
  l" b$ e/ b. S5 z$ Q
      下载源代码
8 l4 j# ^/ O) K        9 |+ C: d, ]' b6 G% V$ \) ]
        引言* L/ J. Y' V. e! J* }9 L1 O: W
        我是C++的初学者,入门都要靠VCKBASE,好在里面有很多适合于初学者的例子,让我少走了很多弯路,为了回馈大家,我也把我最近刚完成的一个简单的小程序提供给大家,让那些曾经和我一样徘徊在C++大门之外的人能快些掌握要领,大家不妨看一看。
# j4 _# w; P# Z  M4 T) `* X        本文以VC知识库第26期 栾义明 先生的《基于API的录音机程序》为基础的,在此深表感谢!相同之处不再重复,我在此基础上增加了将录音保存为wav文件的格式,便于大家参考。! [( w, T' n' W* ]+ v7 m0 e+ X/ ]
基本步骤及思想:设定音频采集参数(采样率、声道等),打开音频设备、准备wave数据头和开辟缓存,操作采集的数据并保存为wav文件。设定音频回放参数,打开回放设备、准备wave数据头和写wave数据。另外样本程序需包含#include <mmsystem.h>和#pragmacomment(lib,"WINMM.LIB")多媒体支持。
1 F! {3 E% `; t' \/ n+ h; Y' F: {        在介绍程序前,需要你对wave文件的格式和相关一些基础概念有所了解,这些均可以在msdn中查找,为方便理解,我们将其整理,如果对这些基础知识已有所了解,可以跳过。+ K. B! K- F, p* W# b$ K7 \5 `: E
        : \$ Y& b, ~7 b4 R: Z# v
      概念1、定义波形数据格式, {' F: ?. u4 k8 C7 ]# ^& N$ U: z1 O
      typedef struct{WORD  wFormatTag;
& P7 w# z+ z8 ?, {: c          WORD nChannels; 9 w* K; M: X: M
          DWORD nSamplesPerSec;
& N2 h7 B. X7 \- B          DWORD nAvgBytesPerSec;4 B" M, j( o5 i4 [2 ^
          WORD  nBlockAlign; 7 }7 W0 v; q# O# f; N! V
          WORD wBitsPerSample; ' S! p! v, O) M5 t, L
          WORD  cbSize; } WAVEFORMATEX;      具体参数解释如下:  O8 i& a9 X& x1 L" Y
      wFormatTag:波形数据的格式,定义在MMREG.H文件中
9 l$ g' Z( F' Y1 ^2 |* R5 G+ a      nChannels:波形数据的通道数:单声道或立体声
9 N0 M9 p" ?  g# ~' l      nSamplesPerSec:采样率,对于PCM格式的波形数据,采样率有8.0 kHz,11.025kHz,22.05 kHz,44.1 kHz等
: v  X+ o! ?. Z; k7 ^+ E3 O      nAvgBytesPerSec:数据率,对于PCM格式的波形数据,数据率等于采样率乘以每样点字节数
, c; {; z' t/ Z, L2 @! Z      nBlockAlign:每个样点字节数$ w( r8 o: a! q1 }( O* i
      wBitsPerSample:采样精度,对于PCM格式的波形数据,采样精度为8或16
2 l, w. \% P/ N9 @      cbSize:附加格式信息的数据块大小) k& N# Q6 I- E. J, S, G/ F
      概念2、定义设备头结构
9 \  l" |9 G/ |0 }" @# T    WAVEHDR定义了指向波形数据缓冲区的设备头。typedef struct { LPSTR lpData;
& Z: p( G2 W3 m- o        DWORD dwBufferLength;
, g6 Y' X8 ^; X; s        DWORD dwBytesRecorded;
0 U, \2 O3 k) M* S+ s" Q2 p        DWORD dwUser;
. \5 R, u2 h& Z9 x4 [        DWORD dwFlags; ! M  [5 |0 e8 O9 Q7 e
        DWORD dwLoops; ; q) I+ [# p, L* s2 i- R
        struct wavehdr_tag * lpNext; 6 n, B: s$ T3 O) A
        DWORD reserved; } WAVEHDR;     lpData:波形数据的缓冲区地址
+ W) t& q+ F9 S, l    dwBufferLength:波形数据的缓冲区地址的长度
2 C1 c# Q  Z; d/ ~" Y    dwBytesRecorded:当设备用于录音时,标志已经录入的数据长度
" k1 q! _( j/ [: v. w8 M    dwUser:用户数据
  V) X, u8 o* s6 @& q2 B" \. W    dwFlags:波形数据的缓冲区的属性* e% \% K& o/ M7 A
    dwLoops:播放循环的次数,仅用于播放控制中
- k. \+ ^+ o( c# T% w) r/ `    lpNext和reserved均为保留值. V. s1 y$ S6 w/ e" T
    注意:上述结构体以及我们在程序中所使用到的“HWAVEIN””HWAVEOUT”结构体均是系统已经存在的,我们只需要对其进行赋值即可。8 r  R# P6 R, a! F, q5 H. D
    概念3、消息处理函数/ d+ {7 |2 J0 {  B2 O) `
    MM_WIM_OPEN    //设备的打开( ^" Z# G. X3 J, J
    MM_WIM_DATA    //设备数据的采集及操作
9 d" e. j( T+ F7 h  W4 ^    MM_WIM_CLOSE   //设备的关闭
% m1 E5 D2 s, t; E$ E7 J7 D$ \% |7 [    相应回放设备的消息分别为MM_WOM_OPEN,MM_WOM_DATA,MM_WOM_CLOSE.
0 y2 E5 h0 \  [    注意:消息处理函数是消息自我驱动的,不需要我们的人为干预。比如:当我们打开设备时,系统会自动调用MM_WIM_OPEN,当我们将数据添加到缓冲区,而缓冲区满时,系统会自动调用MM_WIM_DATA,我们所需要做的,就是对该函数编好相应的源代码。  p3 ^0 E0 a5 m- G, _4 n
    现在,我们进入正题:如何实现一个录音机。& K. V0 U# n" o3 Y
    : S$ J3 g& u* F0 \3 A# R
    ⑴先对WAVEFORMATEX结构体进行赋值,然后为缓冲区分配内存pBuffer1=(PBYTE)malloc(INP_BUFFER_SIZE);
( A- Q9 X8 I4 x7 v+ J: p0 zpBuffer2=(PBYTE)malloc(INP_BUFFER_SIZE);- P0 Z9 f! t- l+ e
对设备头结构体分配内存pWaveHdr1=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));0 A2 R# `3 W2 c1 j6 g3 d
pWaveHdr2=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));8 [1 {4 N0 K. N# z1 e
然后使用wave音频相关函数对输入数据进行操作:
2 t# x6 i2 B4 J/ q5 ~: P3 D
% u" H- u( ~8 i/ A①为波形输入设备准备缓冲区waveInPrepareHeader(hWaveIn,pWaveHdr1,sizeof(WAVEHDR));+ E5 s) Z, L5 y- _( D+ @& ]1 L
waveInPrepareHeader(hWaveIn,pWaveHdr2,sizeof(WAVEHDR));
8 @3 T! {1 E8 n0 D②为波形输入设备添加缓冲区waveInAddBuffer (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;
: N0 G- D- h. d# m) V; j! M9 O  HwaveInAddBuffer (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;
9 k& T3 x/ s/ M9 I1 f- x③启动声音输入设备,将输入数据写入内存waveInStart (hWaveIn) ;⑵编写消息处理函数,其中,MM_WIM_DATA函数是本程序的核心。其主要作用是将输入数据另行保存在一缓冲区内(pSaveBuffer),该缓冲区的长度将随着已录入数据的大小而增加,从而实现保存输入话音数据的功能。同时,可将缓冲区内数据保存为wav文件。其具体实现如下:CFile m_file;
# o: M' V1 e7 g' K, T6 F8 t& pCFileException fileException;8 `9 @' J5 @8 x" t' d* g7 ]4 M( ]( {
CString m_csFileName= "F:\\audio.wav";//保存路径
5 G* S) a' k7 T8 ^3 Y+ A; sm_file.Open(m_csFileName,CFile::modeCreate|CFile::modeReadWrite, &fileException);
& y3 m8 m9 n/ ], MDWORD m_WaveHeaderSize = 38;: y* |+ [1 K( D- `7 ]
DWORD m_WaveFormatSize = 18;* s: [2 w: v% @1 U0 P0 e
m_file.SeekToBegin();, _( B3 D' v6 k6 m3 i: x4 H8 Q1 h
m_file.Write("RIFF",4);5 O+ m3 f4 r5 W, T" Z% z
unsigned int Sec=(sizeof pSaveBuffer + m_WaveHeaderSize);7 J% c2 s: b3 E8 m
m_file.Write(&Sec,sizeof(Sec));
  x/ U! P) v% ]: F% ]2 M6 {m_file.Write("WAVE",4);
* b5 j2 j4 B  `6 Nm_file.Write("fmt ",4);
' E$ u5 q" q/ |! P* ^m_file.Write(&m_WaveFormatSize,sizeof(m_WaveFormatSize));( B7 D0 M  A( c6 }: ^
m_file.Write(&waveform.wFormatTag,sizeof(waveform.wFormatTag));
0 D# T# e, M5 p5 @m_file.Write(&waveform.nChannels,sizeof(waveform.nChannels));
0 A% N% g6 C8 Z+ ^) B7 I2 am_file.Write(&waveform.nSamplesPerSec,sizeof(waveform.nSamplesPerSec));& _; m5 J/ K& C' B9 w1 x* x
m_file.Write(&waveform.nAvgBytesPerSec,sizeof(waveform.nAvgBytesPerSec));, I8 r- d) A" {/ O. I
m_file.Write(&waveform.nBlockAlign,sizeof(waveform.nBlockAlign));
; E% L0 v5 N* W. o2 F, sm_file.Write(&waveform.wBitsPerSample,sizeof(waveform.wBitsPerSample));  a) o9 W  w) L- g5 {4 z! q$ q
m_file.Write(&waveform.cbSize,sizeof(waveform.cbSize));
4 Q' I/ }0 o& @/ y/ ^: X3 E7 Vm_file.Write("data",4);0 s, r# M- `7 ?! A' d
m_file.Write(&dwDataLength,sizeof(dwDataLength));; D! h# E( h$ B% ^1 V
m_file.Write(pSaveBuffer,dwDataLength);; {2 w0 i3 Q; Z5 {; D& m
m_file.Seek(dwDataLength,CFile::begin);+ H' I. K/ P  R/ I  E; ?' z
m_file.Close();
8 R6 G2 g- q( P& N, B; [: E! s存在的问题:+ m/ o7 ^# z0 c0 G3 }: W7 h  m) p
我们也才开始vc学习,只是将自己了解的知识与和我们水平相当的新手们分享,希望一起提高。本程序有时不稳定,但音质很好,可能还有尚未暴露的错误,恳请广大高手们不吝赐教。E-mail: xuejing0103@126.comsmilewenjuan@yahoo.com.cn# d$ z7 i3 G1 S

) w5 s& b$ x; G原文:http://www.vckbase.com/document/viewdoc/?id=1800
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2025-12-13 10:11 , Processed in 0.020815 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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