不用控件,而根据Wave文件的格式播放
问几个问题:
1。取得文件头信息后,后面是PCM数据,请问怎么让声卡播放PCM数据?能否给例子?
2。如果有资料,请贴上看看,谢谢大家

解决方案 »

  1.   

    先用waveOutOpen打开设备,再读几块数据到缓冲waveOutWrite,在MM_WOM_DONE事件中循环读数据到缓冲就行.
      

  2.   

    // 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();
      

  3.   

    请解释一下,如果我不用API PlaySound函数,如何播放?我想从底层做起,学学而已,请大家帮忙!
      

  4.   

    《windows 程序设计》上面说的挺详细的,你有没有看过?
      

  5.   

    用WaveOut系列函数
    录音用WaveIn系列函数
      

  6.   

    // 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
    #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_)
      

  7.   

    // WaveMix.cpp: implementation of the CWaveMix class.
    //
    //////////////////////////////////////////////////////////////////////#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;
    }
      

  8.   

    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;
    }
    }
      

  9.   

    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(..)中清除赋
    给输入、输出设备的音频数据块。  */