如何编程读取Wave文件数据并指挥声卡播放Wave文件? 不用控件,而根据Wave文件的格式播放问几个问题:1。取得文件头信息后,后面是PCM数据,请问怎么让声卡播放PCM数据?能否给例子?2。如果有资料,请贴上看看,谢谢大家 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 先用waveOutOpen打开设备,再读几块数据到缓冲waveOutWrite,在MM_WOM_DONE事件中循环读数据到缓冲就行. // Wave.h#ifndef __WAVE_H__#define __WAVE_H__#include <mmsystem.h>#import <winmm.lib>class CWave{public: CWave(); CWave( const char * ); CWave( const char *, HINSTANCE ); CWave( int, HINSTANCE ); ~CWave(); int DeviceCount( void ); BOOL Load( const char * ); BOOL Load( const char *, HINSTANCE ); BOOL Load( int, HINSTANCE ); BOOL Play( BOOL bLoop = FALSE ); BOOL PlayFromDisk( const char * ); BOOL PlayFromRes( const char *, HINSTANCE ); BOOL PlayFromRes( int, HINSTANCE ); BOOL Stop( void ); BOOL Close( void ); BOOL IsLoaded( void );protected: void InitVars( void ); int m_nDevices; BOOL m_bLoaded; char *m_lpSoundData; HANDLE m_hResHandle;};#endif// Wave.cpp#include "stdafx.h"#include "Wave.h"#include"Winuser.h"CWave::CWave(){ InitVars();}CWave::CWave( const char *lpszFilename ){ InitVars(); Load( lpszFilename );}CWave::CWave( const char *lpszResID, HINSTANCE hInstance ){ InitVars(); Load( lpszResID, hInstance );}CWave::CWave( int nResID, HINSTANCE hInstance ){ InitVars(); Load( nResID, hInstance );}void CWave::InitVars( void ){ m_bLoaded = FALSE; m_lpSoundData = NULL; m_hResHandle = NULL; m_nDevices = waveOutGetNumDevs();}CWave::~CWave(){ Close();}int CWave::DeviceCount( void ){ return( m_nDevices );}BOOL CWave::IsLoaded( void ){ return( m_bLoaded );}BOOL CWave::Load( const char *lpszFilename ){ Close(); CFile File; if( !File.Open( lpszFilename, CFile::modeRead ) ) return( FALSE ); DWORD dwFileLength = File.GetLength(); m_lpSoundData = new char [dwFileLength]; if( m_lpSoundData == NULL ) return( FALSE ); if( File.Read( m_lpSoundData, dwFileLength ) != dwFileLength ) return( FALSE ); m_bLoaded = TRUE; return( TRUE );}BOOL CWave::Load( const char *lpszResID, HINSTANCE hInstance ){ Close(); HANDLE hResInfo; hResInfo = FindResource ( hInstance, lpszResID, "WAVE" ); if( hResInfo == NULL ) return( FALSE ); m_hResHandle = LoadResource( hInstance, (HRSRC) hResInfo ); if( m_hResHandle == NULL ) return( FALSE ); m_lpSoundData = (char *) LockResource( m_hResHandle ); if( m_lpSoundData == NULL ) return( FALSE ); m_bLoaded = TRUE; return( TRUE );}BOOL CWave::Load( int nResID, HINSTANCE hInstance ){ Close(); HANDLE hResInfo; hResInfo = FindResource ( hInstance, MAKEINTRESOURCE( nResID ), "WAVE" ); if( hResInfo == NULL ) return( FALSE ); m_hResHandle = LoadResource( hInstance, (HRSRC) hResInfo ); if( m_hResHandle == NULL ) return( FALSE ); m_lpSoundData = (char *) LockResource( m_hResHandle ); if( m_lpSoundData == NULL ) return( FALSE ); m_bLoaded = TRUE; return( TRUE );}BOOL CWave::Play( BOOL bLoop ){ if( !m_bLoaded ) return( FALSE ); Stop(); DWORD dwFlags = SND_MEMORY | SND_ASYNC | SND_NODEFAULT; if( bLoop ) dwFlags |= SND_LOOP; return( PlaySound( m_lpSoundData, NULL, dwFlags ) );}BOOL CWave::PlayFromDisk( const char *lpszFilename ){ Stop(); return( PlaySound( lpszFilename, NULL, SND_FILENAME | SND_SYNC | SND_NODEFAULT ) );}BOOL CWave::PlayFromRes( const char *lpszResID, HINSTANCE hInstance ){ return( PlaySound( lpszResID, hInstance, SND_RESOURCE | SND_SYNC | SND_NODEFAULT ) );}BOOL CWave::PlayFromRes( int nResID, HINSTANCE hInstance ){ return( PlaySound( MAKEINTRESOURCE( nResID ), hInstance, SND_RESOURCE | SND_SYNC | SND_NODEFAULT ) );}BOOL CWave::Stop( void ){ return( PlaySound( NULL, NULL, NULL ) );}BOOL CWave::Close( void ){ Stop(); if( m_hResHandle != NULL ){ UnlockResource( m_hResHandle ); FreeResource( m_hResHandle ); } else if( m_lpSoundData != NULL ) delete [] m_lpSoundData; m_hResHandle = NULL; m_lpSoundData = NULL; return( TRUE );}用这个把,很好用的CWave m_wave;m_wave.Load(IDR_WAVE1,AfxGetInstanceHandle());m_wave.Play(); 请解释一下,如果我不用API PlaySound函数,如何播放?我想从底层做起,学学而已,请大家帮忙! 《windows 程序设计》上面说的挺详细的,你有没有看过? 用WaveOut系列函数录音用WaveIn系列函数 // WaveMix.h: interface for the CWaveMix class.////////////////////////////////////////////////////////////////////////#if !defined(AFX_WAVEMIX_H__A44E17C0_5869_11D6_9B5E_00055DA0ABC3__INCLUDED_)#define AFX_WAVEMIX_H__A44E17C0_5869_11D6_9B5E_00055DA0ABC3__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000#include "mmsystem.h"#ifdef WIN32#define WAVDATA BYTE#else#define WAVDATA BYTE _huge#define WAVEFORMATEX PCMWAVEFORMAT #endif#ifdef WIN32#define WAV16DATA WORD#else#define WAV16DATA WORD _huge#endifclass CWaveMix {public: void MixData(PBYTE lpWaveSrc[],PBYTE lpWavDst,int iChannels,WORD wLen); CWaveMix(); virtual ~CWaveMix(); int Open(char*); //打开一个WAV文件 int Play(HWND); //播放一个WAV文件 int Add(char*); //往正在播放的WAV设备中添加WAV 文件 int Stop(); //停止播放 int Close(); //关闭设备 int Continue(); DWORD DataSize; WAVDATA* lpData;private: BOOL OpenFlage; HGLOBAL hData; DWORD DataSize_start; PCMWAVEFORMAT pFormat; WAVEHDR WaveHead; HWAVEOUT hWaveOut; int m_Channels;};#endif // !defined(AFX_WAVEMIX_H__A44E17C0_5869_11D6_9B5E_00055DA0ABC3__INCLUDED_) // WaveMix.cpp: implementation of the CWaveMix class.////////////////////////////////////////////////////////////////////////#include "stdafx.h"#include "WavPlay.h"#include "WaveMix.h"#ifdef _DEBUG#undef THIS_FILEstatic char THIS_FILE[]=__FILE__;#define new DEBUG_NEW#endif//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////CWaveMix::CWaveMix(){ memset(this,0,sizeof(CWaveMix));}CWaveMix::~CWaveMix(){ Close();}int CWaveMix::Open(char* name){ HMMIO hMmio; MMCKINFO pinfo; MMCKINFO cinfo; if(hMmio) Close(); //打开WAV文件,返回一个HMMIO句柄 hMmio=mmioOpen(name,NULL,MMIO_READ); if(!hMmio) return FALSE; OpenFlage=1; //查找父块"wave"; pinfo.fccType=mmioFOURCC('W','A','V','E'); if(mmioDescend(hMmio,&pinfo,NULL,MMIO_FINDRIFF)) goto FALSE_END; //查找子块"fmt" parent"riff"; cinfo.ckid=mmioFOURCC('f','m','t',' '); if(mmioDescend(hMmio,&cinfo,&pinfo,MMIO_FINDCHUNK)) goto FALSE_END; mmioRead(hMmio,(LPSTR)&pFormat,sizeof(PCMWAVEFORMAT));//cinfo.cksize); if(pFormat.wf.wFormatTag!=WAVE_FORMAT_PCM) goto FALSE_END; //跳入块"FMT" mmioAscend(hMmio,&cinfo,0); //查找数据块 cinfo.ckid=mmioFOURCC('d','a','t','a'); if(mmioDescend(hMmio,&cinfo,&pinfo,MMIO_FINDCHUNK)) goto FALSE_END; DataSize=cinfo.cksize; //读取数据 hData=GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,DataSize); lpData=(WAVDATA*)GlobalLock(hData); if( !hData || !lpData ) goto FALSE_END; if(mmioRead(hMmio,(HPSTR)lpData,DataSize)!=(LRESULT)DataSize) goto FALSE_END; //close and return mmioClose(hMmio,MMIO_FHOPEN); return TRUE;FALSE_END: if(hMmio)mmioClose(hMmio,MMIO_FHOPEN); if(lpData)LocalUnlock(hData); if(hData)GlobalFree(hData); memset(this,0,sizeof(CWaveMix)); return 0;}int CWaveMix::Play(HWND hP){ if(!OpenFlage) return FALSE; //检测系统播放功能 if(waveOutOpen(NULL,WAVE_MAPPER,(WAVEFORMATEX*)&pFormat,NULL,NULL,WAVE_FORMAT_QUERY)) return Close(); if(waveOutOpen(&hWaveOut,WAVE_MAPPER,(WAVEFORMATEX*)&pFormat,(DWORD)hP,0,CALLBACK_WINDOW)) return Close(); WaveHead.lpData=(LPSTR)lpData; WaveHead.dwBufferLength=DataSize; WaveHead.dwFlags=0L; WaveHead.dwLoops=0L; DataSize_start=DataSize; //往WAV设备中添加数据 if(waveOutPrepareHeader(hWaveOut,&WaveHead, sizeof(WAVEHDR))) return Close(); if(waveOutWrite(hWaveOut,&WaveHead,sizeof(WAVEHDR))) return Close(); return TRUE;} int CWaveMix::Continue(){ CWaveMix wav; if(!wav.Open("2.wav")) return FALSE; memcpy(lpData,wav.lpData,DataSize);// WaveHead.lpData=(LPSTR)wav.lpData; // WaveHead.dwBufferLength=wav.DataSize; if(waveOutPrepareHeader(hWaveOut,&WaveHead, sizeof(WAVEHDR))) return Close(); if(waveOutWrite(hWaveOut,&WaveHead,sizeof(WAVEHDR))) return Close(); return TRUE;}//#define min(a, b) (((a) < (b)) ? (a) : (b))//把多个WAVE文件混音播放int CWaveMix::Add(char* name){ register int x; if(!OpenFlage) return Open(name); CWaveMix wav; if(!wav.Open(name)) return FALSE; MMTIME time; //获得WAV文件当前播放位置 time.wType=TIME_BYTES; if(waveOutGetPosition(hWaveOut,&time,sizeof(MMTIME))) time.u.cb=0; DWORD start=((time.u.cb>>1)<<1); DWORD end=min(DataSize_start,wav.DataSize);// DWORD end=wav.DataSize; register WAVDATA* lpd=lpData+start; for(register DWORD i=0;i<end;i++) { //将两组WAV文件数据相加,并检测数据大小是否合法,如果 //数据大小越界,则分别取最大值和最小值 x=(((*(lpd+i))+(*(wav.lpData+i))))-128; if(x<0) x=0; if(x>255) x=255; *(lpd+i)=(BYTE)(x); } return TRUE;}int CWaveMix::Stop(){ return !waveOutReset(hWaveOut);}int CWaveMix::Close(){ if(hWaveOut) { waveOutReset(hWaveOut); waveOutUnprepareHeader(hWaveOut,&WaveHead,sizeof(WAVEHDR)); waveOutClose(hWaveOut); } if(lpData)LocalUnlock(hData); if(hData)GlobalFree(hData); memset(this,0,sizeof(CWaveMix)); return 0;}void CWaveMix::MixData(PBYTE lpWavSrc[], PBYTE lpWavDst, int iChannels, WORD wLen){ int i,iSum; for(int j=0;j<wLen;j++) { iSum=128;//静音时数值为128 for(i=0;i<iChannels;i++) iSum=iSum+*(lpWavSrc[i]+j)-128; if(iSum<0) iSum=0; if(iSum>255) iSum=255; *lpWavDst++=iSum; }} Windows低层波形音频数据块结构 WAVEHDR,其声明如下: type struct{ LPSTR lpData; //指向锁定的数据缓冲区的指针 DWORD dwBufferLength; //数据缓冲区的大小 DWORD dwByteRecorded; //录音时指明缓冲区中的数据量 DWORD dwUser; //用户数据 DWORD dwFlag; //提供缓冲区信息的标志 DWORD dwLoops; //循环播放的次数 struct wavehdr_tag *lpNext; //保留 DWORD reserved; //保留 } WAVEHDR; 常用mmio函数及实现过程简介:mmioOpen( ) 打开一个RIFF文件mmioDescend ( ) 进入块mmioRead( ); 该取RIFF文件mmioAscend ( ); 跳出块mmioClose( ); 关闭PIFF文件对于块来说,进入块和跳出块是配对的。读取WAV文件的读取过程:mmioOpen( ) 打开文件↓mmioDescend ("WAVE") 进入"fmt"块↓mmioRead( ) 读取WAVE文件格式信息↓mmioAscend ( ) 跳出"fmt"块↓mmioDescend ("data") 进入"data"块↓mmioRead( ) 读取WAVE数据信息↓mmioClose( ) 关闭文件。输出WAV文件的过程:WaveOutOpen () 打开一个输出设备↓WaveOutPrepareHeader() 准备WAVE数据头。↓WaveOutWrite() 将数据写入设备并开始播放↓WaveOutReset() 停止播放并重置管理器↓WaveOutClose() 并闭播放设备↓WaveOutUnpareHeader() 清理用WaveOutPrepareHeader准备的Wave。在使用低级音频函数播放音频时,应用程序必须不断地向设备驱动程序提供数据块,直到播放结束。WINDOWS提供两种方法管理波形重放:一是使用窗口消息管理,二是使用低级回调函数管理。另外,通过使用waveOutPause、waveOutRestart和waveOutReset来进行暂停、重新启动和停止播放录音开始后,每当有采样数据填满数据块后,设备驱动程序就会发消息MM_WIM_DATA给用户窗口,相应的消息回调函数OnMmWimData(...)对数据块中的采样数据进行处理,然后就可以发送给输出设备进行回放,每当一个音频数据块播放完毕,设备驱动程序又会发出消息MM_WOM_DONE,相应的消息回调函数 OnMmWomDone(...)记录音频数据并经必要准备后重新发送给输入设备,以准备接收后续的采样数据。这样,最初为输入设备准备的音频数据块就在消息的控制下,在输入、输出设备间循环使用,无需人为控制实现了实时采集、处理和播放。当结束通话时要关闭音频输入设备,这时音频设备驱动程序会发送MM_WIM_CLOSE消息,可在相应的消息函数OnMmWimClose(..)中清除赋给输入、输出设备的音频数据块。 */ MFC显示跟打印结果不一致的问题? 取网站文件 在VC中用DX的问题 怎样在两个视图之间进行通信,最快的方法 关于udp的问题 IPC连接是什么东西??? c++小问题,如何返回两个参数的值 怎么会变成日文?? 新手问题 help me!在VIEW中画了个BUTTON,用右键单击它,但是出来的浮动菜单,不能响应 关于ConnectionPoint的问题 在mdi框架中,同时显示两个form子窗口,其中一个输入,另一个显示,如何实现输入内容改变,显示内容同步改变?
#define __WAVE_H__#include <mmsystem.h>
#import <winmm.lib>
class CWave
{public:
CWave();
CWave( const char * );
CWave( const char *, HINSTANCE );
CWave( int, HINSTANCE );
~CWave(); int DeviceCount( void ); BOOL Load( const char * );
BOOL Load( const char *, HINSTANCE );
BOOL Load( int, HINSTANCE ); BOOL Play( BOOL bLoop = FALSE );
BOOL PlayFromDisk( const char * );
BOOL PlayFromRes( const char *, HINSTANCE );
BOOL PlayFromRes( int, HINSTANCE );
BOOL Stop( void );
BOOL Close( void ); BOOL IsLoaded( void );protected:
void InitVars( void ); int m_nDevices;
BOOL m_bLoaded;
char *m_lpSoundData;
HANDLE m_hResHandle;};#endif
// Wave.cpp#include "stdafx.h"
#include "Wave.h"
#include"Winuser.h"CWave::CWave()
{ InitVars();}CWave::CWave( const char *lpszFilename )
{ InitVars();
Load( lpszFilename );}CWave::CWave( const char *lpszResID, HINSTANCE hInstance )
{ InitVars();
Load( lpszResID, hInstance );}CWave::CWave( int nResID, HINSTANCE hInstance )
{ InitVars();
Load( nResID, hInstance );}void CWave::InitVars( void )
{ m_bLoaded = FALSE;
m_lpSoundData = NULL;
m_hResHandle = NULL;
m_nDevices = waveOutGetNumDevs();}CWave::~CWave()
{ Close();}int CWave::DeviceCount( void )
{ return( m_nDevices );}BOOL CWave::IsLoaded( void )
{ return( m_bLoaded );}BOOL CWave::Load( const char *lpszFilename )
{ Close(); CFile File;
if( !File.Open( lpszFilename, CFile::modeRead ) )
return( FALSE ); DWORD dwFileLength = File.GetLength();
m_lpSoundData = new char [dwFileLength];
if( m_lpSoundData == NULL )
return( FALSE ); if( File.Read( m_lpSoundData, dwFileLength )
!= dwFileLength )
return( FALSE ); m_bLoaded = TRUE; return( TRUE );}BOOL CWave::Load( const char *lpszResID, HINSTANCE hInstance )
{ Close(); HANDLE hResInfo;
hResInfo = FindResource ( hInstance, lpszResID, "WAVE" );
if( hResInfo == NULL )
return( FALSE ); m_hResHandle = LoadResource( hInstance, (HRSRC) hResInfo );
if( m_hResHandle == NULL )
return( FALSE ); m_lpSoundData = (char *) LockResource( m_hResHandle );
if( m_lpSoundData == NULL )
return( FALSE ); m_bLoaded = TRUE; return( TRUE );}BOOL CWave::Load( int nResID, HINSTANCE hInstance )
{ Close(); HANDLE hResInfo;
hResInfo = FindResource ( hInstance,
MAKEINTRESOURCE( nResID ), "WAVE" );
if( hResInfo == NULL )
return( FALSE ); m_hResHandle = LoadResource( hInstance, (HRSRC) hResInfo );
if( m_hResHandle == NULL )
return( FALSE ); m_lpSoundData = (char *) LockResource( m_hResHandle );
if( m_lpSoundData == NULL )
return( FALSE ); m_bLoaded = TRUE; return( TRUE );}BOOL CWave::Play( BOOL bLoop )
{ if( !m_bLoaded )
return( FALSE ); Stop();
DWORD dwFlags = SND_MEMORY | SND_ASYNC | SND_NODEFAULT;
if( bLoop )
dwFlags |= SND_LOOP; return( PlaySound( m_lpSoundData, NULL, dwFlags ) );}BOOL CWave::PlayFromDisk( const char *lpszFilename )
{ Stop();
return( PlaySound( lpszFilename, NULL,
SND_FILENAME | SND_SYNC | SND_NODEFAULT ) );}BOOL CWave::PlayFromRes( const char *lpszResID,
HINSTANCE hInstance )
{ return( PlaySound( lpszResID, hInstance,
SND_RESOURCE | SND_SYNC | SND_NODEFAULT ) );}BOOL CWave::PlayFromRes( int nResID, HINSTANCE hInstance )
{ return( PlaySound( MAKEINTRESOURCE( nResID ),
hInstance, SND_RESOURCE | SND_SYNC | SND_NODEFAULT ) );}BOOL CWave::Stop( void )
{ return( PlaySound( NULL, NULL, NULL ) );}BOOL CWave::Close( void )
{ Stop(); if( m_hResHandle != NULL ){
UnlockResource( m_hResHandle );
FreeResource( m_hResHandle );
}
else if( m_lpSoundData != NULL )
delete [] m_lpSoundData; m_hResHandle = NULL;
m_lpSoundData = NULL; return( TRUE );}用这个把,很好用的
CWave m_wave;
m_wave.Load(IDR_WAVE1,AfxGetInstanceHandle());
m_wave.Play();
录音用WaveIn系列函数
//
//////////////////////////////////////////////////////////////////////#if !defined(AFX_WAVEMIX_H__A44E17C0_5869_11D6_9B5E_00055DA0ABC3__INCLUDED_)
#define AFX_WAVEMIX_H__A44E17C0_5869_11D6_9B5E_00055DA0ABC3__INCLUDED_#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000#include "mmsystem.h"
#ifdef WIN32
#define WAVDATA BYTE
#else
#define WAVDATA BYTE _huge
#define WAVEFORMATEX PCMWAVEFORMAT
#endif#ifdef WIN32
#define WAV16DATA WORD
#else
#define WAV16DATA WORD _huge
#endif
class CWaveMix
{
public:
void MixData(PBYTE lpWaveSrc[],PBYTE lpWavDst,int iChannels,WORD wLen);
CWaveMix();
virtual ~CWaveMix();
int Open(char*); //打开一个WAV文件
int Play(HWND); //播放一个WAV文件
int Add(char*); //往正在播放的WAV设备中添加WAV 文件
int Stop(); //停止播放
int Close(); //关闭设备
int Continue();
DWORD DataSize;
WAVDATA* lpData;
private:
BOOL OpenFlage;
HGLOBAL hData;
DWORD DataSize_start; PCMWAVEFORMAT pFormat;
WAVEHDR WaveHead;
HWAVEOUT hWaveOut; int m_Channels;
};#endif // !defined(AFX_WAVEMIX_H__A44E17C0_5869_11D6_9B5E_00055DA0ABC3__INCLUDED_)
//
//////////////////////////////////////////////////////////////////////#include "stdafx.h"
#include "WavPlay.h"
#include "WaveMix.h"#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////CWaveMix::CWaveMix()
{
memset(this,0,sizeof(CWaveMix));
}CWaveMix::~CWaveMix()
{
Close();
}int CWaveMix::Open(char* name)
{
HMMIO hMmio;
MMCKINFO pinfo;
MMCKINFO cinfo; if(hMmio)
Close(); //打开WAV文件,返回一个HMMIO句柄
hMmio=mmioOpen(name,NULL,MMIO_READ);
if(!hMmio)
return FALSE;
OpenFlage=1; //查找父块"wave";
pinfo.fccType=mmioFOURCC('W','A','V','E');
if(mmioDescend(hMmio,&pinfo,NULL,MMIO_FINDRIFF))
goto FALSE_END; //查找子块"fmt" parent"riff";
cinfo.ckid=mmioFOURCC('f','m','t',' ');
if(mmioDescend(hMmio,&cinfo,&pinfo,MMIO_FINDCHUNK))
goto FALSE_END; mmioRead(hMmio,(LPSTR)&pFormat,sizeof(PCMWAVEFORMAT));//cinfo.cksize);
if(pFormat.wf.wFormatTag!=WAVE_FORMAT_PCM)
goto FALSE_END; //跳入块"FMT"
mmioAscend(hMmio,&cinfo,0); //查找数据块
cinfo.ckid=mmioFOURCC('d','a','t','a');
if(mmioDescend(hMmio,&cinfo,&pinfo,MMIO_FINDCHUNK))
goto FALSE_END;
DataSize=cinfo.cksize;
//读取数据
hData=GlobalAlloc(GMEM_MOVEABLE
| GMEM_SHARE,DataSize);
lpData=(WAVDATA*)GlobalLock(hData);
if( !hData || !lpData ) goto FALSE_END;
if(mmioRead(hMmio,(HPSTR)lpData,DataSize)!=(LRESULT)DataSize)
goto FALSE_END; //close and return
mmioClose(hMmio,MMIO_FHOPEN);
return TRUE;FALSE_END:
if(hMmio)mmioClose(hMmio,MMIO_FHOPEN);
if(lpData)LocalUnlock(hData);
if(hData)GlobalFree(hData);
memset(this,0,sizeof(CWaveMix));
return 0;
}int CWaveMix::Play(HWND hP)
{
if(!OpenFlage)
return FALSE; //检测系统播放功能
if(waveOutOpen(NULL,WAVE_MAPPER,(WAVEFORMATEX*)&pFormat,NULL,NULL,WAVE_FORMAT_QUERY))
return Close(); if(waveOutOpen(&hWaveOut,WAVE_MAPPER,(WAVEFORMATEX*)&pFormat,(DWORD)hP,0,CALLBACK_WINDOW))
return Close(); WaveHead.lpData=(LPSTR)lpData;
WaveHead.dwBufferLength=DataSize;
WaveHead.dwFlags=0L;
WaveHead.dwLoops=0L;
DataSize_start=DataSize; //往WAV设备中添加数据
if(waveOutPrepareHeader(hWaveOut,&WaveHead, sizeof(WAVEHDR)))
return Close(); if(waveOutWrite(hWaveOut,&WaveHead,sizeof(WAVEHDR)))
return Close(); return TRUE;
}
{
CWaveMix wav;
if(!wav.Open("2.wav"))
return FALSE;
memcpy(lpData,wav.lpData,DataSize);
// WaveHead.lpData=(LPSTR)wav.lpData;
// WaveHead.dwBufferLength=wav.DataSize;
if(waveOutPrepareHeader(hWaveOut,&WaveHead, sizeof(WAVEHDR)))
return Close();
if(waveOutWrite(hWaveOut,&WaveHead,sizeof(WAVEHDR)))
return Close();
return TRUE;
}//#define min(a, b) (((a) < (b)) ? (a) : (b))
//把多个WAVE文件混音播放
int CWaveMix::Add(char* name)
{
register int x;
if(!OpenFlage)
return Open(name); CWaveMix wav;
if(!wav.Open(name))
return FALSE; MMTIME time;
//获得WAV文件当前播放位置
time.wType=TIME_BYTES;
if(waveOutGetPosition(hWaveOut,&time,sizeof(MMTIME)))
time.u.cb=0;
DWORD start=((time.u.cb>>1)<<1);
DWORD end=min(DataSize_start,wav.DataSize);
// DWORD end=wav.DataSize;
register WAVDATA* lpd=lpData+start;
for(register DWORD i=0;i<end;i++)
{
//将两组WAV文件数据相加,并检测数据大小是否合法,如果
//数据大小越界,则分别取最大值和最小值
x=(((*(lpd+i))+(*(wav.lpData+i))))-128;
if(x<0)
x=0;
if(x>255)
x=255;
*(lpd+i)=(BYTE)(x);
}
return TRUE;
}int CWaveMix::Stop()
{
return !waveOutReset(hWaveOut);
}int CWaveMix::Close()
{
if(hWaveOut)
{
waveOutReset(hWaveOut);
waveOutUnprepareHeader(hWaveOut,&WaveHead,sizeof(WAVEHDR));
waveOutClose(hWaveOut);
}
if(lpData)LocalUnlock(hData);
if(hData)GlobalFree(hData);
memset(this,0,sizeof(CWaveMix));
return 0;
}
void CWaveMix::MixData(PBYTE lpWavSrc[], PBYTE lpWavDst, int iChannels, WORD wLen)
{
int i,iSum;
for(int j=0;j<wLen;j++)
{
iSum=128;//静音时数值为128
for(i=0;i<iChannels;i++)
iSum=iSum+*(lpWavSrc[i]+j)-128;
if(iSum<0) iSum=0;
if(iSum>255) iSum=255;
*lpWavDst++=iSum;
}
}
LPSTR lpData; //指向锁定的数据缓冲区的指针
DWORD dwBufferLength; //数据缓冲区的大小
DWORD dwByteRecorded; //录音时指明缓冲区中的数据量
DWORD dwUser; //用户数据
DWORD dwFlag; //提供缓冲区信息的标志
DWORD dwLoops; //循环播放的次数
struct wavehdr_tag *lpNext; //保留
DWORD reserved; //保留
} WAVEHDR;
常用mmio函数及实现过程简介:
mmioOpen( ) 打开一个RIFF文件
mmioDescend ( ) 进入块
mmioRead( ); 该取RIFF文件
mmioAscend ( ); 跳出块
mmioClose( ); 关闭PIFF文件
对于块来说,进入块和跳出块是配对的。
读取WAV文件的读取过程:
mmioOpen( ) 打开文件
↓
mmioDescend ("WAVE") 进入"fmt"块
↓
mmioRead( ) 读取WAVE文件格式信息
↓
mmioAscend ( ) 跳出"fmt"块
↓
mmioDescend ("data") 进入"data"块
↓
mmioRead( ) 读取WAVE数据信息
↓
mmioClose( ) 关闭文件。输出WAV文件的过程:
WaveOutOpen () 打开一个输出设备
↓
WaveOutPrepareHeader() 准备WAVE数据头。
↓
WaveOutWrite() 将数据写入设备并开始播放
↓
WaveOutReset() 停止播放并重置管理器
↓
WaveOutClose() 并闭播放设备
↓
WaveOutUnpareHeader() 清理用WaveOutPrepareHeader准备的Wave。
在使用低级音频函数播放音频时,应用程序必须不断地向设备驱动程序提供数据块,直到播放结束。
WINDOWS提供两种方法管理波形重放:一是使用窗口消息管理,二是使用低级回调函数管理。
另外,通过使用waveOutPause、waveOutRestart和waveOutReset来进行暂停、重新启动和停止播放录音开始后,每当有采样数据填满数据块后,设备驱动程序就会发消息MM_WIM_DATA给用户窗口,
相应的消息回调函数OnMmWimData(...)对数据块中的采样数据进行处理,然后就可以发送给输出
设备进行回放,每当一个音频数据块播放完毕,设备驱动程序又会发出消息MM_WOM_DONE,相应
的消息回调函数 OnMmWomDone(...)记录音频数据并经必要准备后重新发送给输入设备,以准备
接收后续的采样数据。这样,最初为输入设备准备的音频数据块就在消息的控制下,在输入、输出
设备间循环使用,无需人为控制实现了实时采集、处理和播放。当结束通话时要关闭音频输入设备,
这时音频设备驱动程序会发送MM_WIM_CLOSE消息,可在相应的消息函数OnMmWimClose(..)中清除赋
给输入、输出设备的音频数据块。 */