VC++中WAV音频文件操作的方法,谁能给一个封装好的类了,包括读写操作。
谢谢!wav

解决方案 »

  1.   

    头文件:
    #ifndef CLASS_WAV_FILE_H_
    #define CLASS_WAV_FILE_H_#define WAVEFILE_READ   1
    #define WAVEFILE_WRITE  2
    #include <Windows.h>
    #include <MMSystem.h>
    #pragma comment(lib,"winmm.lib")class CWaveFile
    {
    public:
        WAVEFORMATEX* m_pwfx;        // Pointer to WAVEFORMATEX structure
        HMMIO         m_hmmio;       // MM I/O handle for the WAVE
        MMCKINFO      m_ck;          // Multimedia RIFF chunk
        MMCKINFO      m_ckRiff;      // Use in opening a WAVE file
        DWORD         m_dwSize;      // The size of the wave file
        MMIOINFO      m_mmioinfoOut;
        DWORD         flag_;
        BYTE*         m_pbData;
        BYTE*         m_pbDataCur;
        ULONG         m_ulDataSize;
        CHAR*         m_pResourceBuffer;
        WAVEFORMATEX  wave_format_;protected:
        HRESULT ReadMMIO();
        HRESULT WriteMMIO( WAVEFORMATEX *pwfxDest );public:
        CWaveFile();
        
        ~CWaveFile();
        
        HRESULT Open( 
            LPTSTR filename, 
            DWORD flag,
            UINT channels, 
            ULONG samples_per_sec, 
            UINT bits_per_sample);    HRESULT Close();    HRESULT Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead );
        
        HRESULT Write( UINT nSizeToWrite, BYTE* pbData, UINT* pnSizeWrote );    DWORD   GetSize();
        
        HRESULT ResetFile();
        
        WAVEFORMATEX* GetFormat() { return m_pwfx; };
    };#endif // ! CLASS_WAV_FILE_H_
    [/code]
      

  2.   

    cpp文件:#include "stdafx.h"
    #include "common-header.h"
    #include "WavFile.h"CWaveFile::CWaveFile()
    {
        m_pwfx    = NULL;
        m_hmmio   = NULL;
        m_pResourceBuffer = NULL;
        m_dwSize  = 0;}CWaveFile::~CWaveFile()
    {
        Close();
        SAFE_DELETE_ARRAY( m_pwfx );
    }
    HRESULT CWaveFile::Open( LPTSTR filename, DWORD flag, UINT channels, ULONG samples_per_sec, UINT bits_per_sample )
    {
        wave_format_.cbSize                  = 0;
        wave_format_.wFormatTag              = WAVE_FORMAT_PCM;
        wave_format_.nChannels               = channels;
        wave_format_.nSamplesPerSec          = samples_per_sec;
        wave_format_.wBitsPerSample          = bits_per_sample;
        wave_format_.nBlockAlign             = wave_format_.nChannels * ( wave_format_.wBitsPerSample / 8 );
        wave_format_.nAvgBytesPerSec         = wave_format_.nBlockAlign * wave_format_.nSamplesPerSec;    HRESULT hr;    flag_ = flag;
        if( flag_ == WAVEFILE_READ ) {
            if( filename == NULL )
                return E_INVALIDARG;        SAFE_DELETE_ARRAY( m_pwfx );        m_hmmio = mmioOpen( filename, NULL, MMIO_ALLOCBUF | MMIO_READ );        if( NULL == m_hmmio ) {
                HRSRC   hResInfo;
                HGLOBAL hResData;
                DWORD   dwSize;
                VOID   *pvRes;            // Loading it as a file failed, so try it as a resource
                if( NULL == ( hResInfo = FindResource( NULL, filename, TEXT("WAVE") ) ) ) {
                    if( NULL == ( hResInfo = FindResource( NULL, filename, TEXT("WAV") ) ) )
                        return  E_FAIL;
                }            if( NULL == ( hResData = LoadResource( NULL, hResInfo ) ) )
                    return E_FAIL;            if( 0 == ( dwSize = SizeofResource( NULL, hResInfo ) ) )
                    return E_FAIL;            if( NULL == ( pvRes = LockResource( hResData ) ) )
                    return E_FAIL;            m_pResourceBuffer = new CHAR[ dwSize ];
                memcpy( m_pResourceBuffer, pvRes, dwSize );            MMIOINFO mmioInfo;
                ZeroMemory( &mmioInfo, sizeof(mmioInfo) );
                mmioInfo.fccIOProc = FOURCC_MEM;
                mmioInfo.cchBuffer = dwSize;
                mmioInfo.pchBuffer = (CHAR *) m_pResourceBuffer;            m_hmmio = mmioOpen( NULL, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ );
            }        if( FAILED( hr = ReadMMIO() ) ) {
                // ReadMMIO will fail if its an not a wave file
                mmioClose( m_hmmio, 0 );
                return hr;
            }        if( FAILED( hr = ResetFile() ) )
                return hr;        // After the reset, the size of the wav file is m_ck.cksize so store it now
            m_dwSize = m_ck.cksize;    } else {
            m_hmmio = mmioOpen( filename, NULL, MMIO_ALLOCBUF  |
                                MMIO_READWRITE |
                                MMIO_CREATE );        if( NULL == m_hmmio )
                return E_FAIL;        if( FAILED( hr = WriteMMIO( &wave_format_ ) ) ) {
                mmioClose( m_hmmio, 0 );
                return hr;
            }        if( FAILED( hr = ResetFile() ) )
                return hr;
        }    return hr;
    }HRESULT CWaveFile::ReadMMIO()
    {
        MMCKINFO        ckIn;           // chunk info. for general use.
        PCMWAVEFORMAT   pcmWaveFormat;  // Temp PCM structure to load in.    m_pwfx = NULL;    if( ( 0 != mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) ) )
            return E_FAIL;    // Check to make sure this is a valid wave file
        if( (m_ckRiff.ckid != FOURCC_RIFF) ||
                (m_ckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E') ) )
            return E_FAIL;    // Search the input file for for the 'fmt ' chunk.
        ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');    if( 0 != mmioDescend( m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK ) )
            return E_FAIL;    // Expect the 'fmt' chunk to be at least as large as <PCMWAVEFORMAT>;
        // if there are extra parameters at the end, we'll ignore them
        if( ckIn.cksize < (LONG) sizeof(PCMWAVEFORMAT) )
            return E_FAIL;    // Read the 'fmt ' chunk into <pcmWaveFormat>.
        if( mmioRead( m_hmmio, (HPSTR) &pcmWaveFormat,
                      sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) )
            return E_FAIL;    // Allocate the waveformatex, but if its not pcm format, read the next
        // word, and thats how many extra bytes to allocate.
        if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM ) {
            m_pwfx = (WAVEFORMATEX *)new CHAR[ sizeof(WAVEFORMATEX) ];        if( NULL == m_pwfx )
                return E_FAIL;        // Copy the bytes from the pcm structure to the waveformatex structure
            memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
            m_pwfx->cbSize = 0;
        } else {
            // Read in length of extra bytes.
            WORD cbExtraBytes = 0L;        if( mmioRead( m_hmmio, (CHAR *)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD) )
                return E_FAIL;        m_pwfx = (WAVEFORMATEX *)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ];        if( NULL == m_pwfx )
                return E_FAIL;        // Copy the bytes from the pcm structure to the waveformatex structure
            memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
            m_pwfx->cbSize = cbExtraBytes;        // Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
            if( mmioRead( m_hmmio, (CHAR *)(((BYTE *) & (m_pwfx->cbSize)) + sizeof(WORD)),
                          cbExtraBytes ) != cbExtraBytes ) {
                SAFE_DELETE( m_pwfx );
                return E_FAIL;
            }
        }    // Ascend the input file out of the 'fmt ' chunk.
        if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) ) {
            SAFE_DELETE( m_pwfx );
            return E_FAIL;
        }    return S_OK;
    }HRESULT CWaveFile::WriteMMIO( WAVEFORMATEX *pwfxDest )
    {
        DWORD    dwFactChunk; // Contains the actual fact chunk. Garbage until WaveCloseWriteFile.
        MMCKINFO ckOut1;    dwFactChunk = (DWORD) - 1;    // Create the output file RIFF chunk of form type 'WAVE'.
        m_ckRiff.fccType = mmioFOURCC('W', 'A', 'V', 'E');
        m_ckRiff.cksize = 0;    if( 0 != mmioCreateChunk( m_hmmio, &m_ckRiff, MMIO_CREATERIFF ) )
            return E_FAIL;    // We are now descended into the 'RIFF' chunk we just created.
        // Now create the 'fmt ' chunk. Since we know the size of this chunk,
        // specify it in the MMCKINFO structure so MMIO doesn't have to seek
        // back and set the chunk size after ascending from the chunk.
        m_ck.ckid = mmioFOURCC('f', 'm', 't', ' ');
        m_ck.cksize = sizeof(PCMWAVEFORMAT);    if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
            return E_FAIL;    // Write the PCMWAVEFORMAT structure to the 'fmt ' chunk if its that type.
        if( pwfxDest->wFormatTag == WAVE_FORMAT_PCM ) {
            if( mmioWrite( m_hmmio, (HPSTR) pwfxDest,
                           sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT))
                return E_FAIL;
        } else {
            // Write the variable length size.
            if( (UINT)mmioWrite( m_hmmio, (HPSTR) pwfxDest,
                                 sizeof(*pwfxDest) + pwfxDest->cbSize ) !=
                    ( sizeof(*pwfxDest) + pwfxDest->cbSize ) )
                return E_FAIL;
        }    // Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk.
        if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
            return E_FAIL;    // Now create the fact chunk, not required for PCM but nice to have.  This is filled
        // in when the close routine is called.
        ckOut1.ckid = mmioFOURCC('f', 'a', 'c', 't');
        ckOut1.cksize = 0;    if( 0 != mmioCreateChunk( m_hmmio, &ckOut1, 0 ) )
            return E_FAIL;    if( mmioWrite( m_hmmio, (HPSTR)&dwFactChunk, sizeof(dwFactChunk)) !=
                sizeof(dwFactChunk) )
            return E_FAIL;    // Now ascend out of the fact chunk...
        if( 0 != mmioAscend( m_hmmio, &ckOut1, 0 ) )
            return E_FAIL;    return S_OK;
    }DWORD CWaveFile::GetSize()
    {
        return m_dwSize;
    }HRESULT CWaveFile::ResetFile()
    {
        if( m_hmmio == NULL )
            return CO_E_NOTINITIALIZED;    if( flag_ == WAVEFILE_READ ) {
            // Seek to the data
            if( -1 == mmioSeek( m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC), SEEK_SET ) )
                return E_FAIL;        // Search the input file for the 'data' chunk.
            m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');        if( 0 != mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
                return E_FAIL;
        } else {
            // Create the 'data' chunk that holds the waveform samples.
            m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
            m_ck.cksize = 0;        if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
                return E_FAIL;        if( 0 != mmioGetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
                return E_FAIL;
        }    return S_OK;
    }
      

  3.   

    HRESULT CWaveFile::Read( BYTE *pBuffer, DWORD dwSizeToRead, DWORD *pdwSizeRead )
    {
        MMIOINFO mmioinfoIn; // current status of m_hmmio    if( m_hmmio == NULL )
            return CO_E_NOTINITIALIZED;    if( pBuffer == NULL || pdwSizeRead == NULL )
            return E_INVALIDARG;    if( pdwSizeRead != NULL )
            *pdwSizeRead = 0;    if( 0 != mmioGetInfo( m_hmmio, &mmioinfoIn, 0 ) )
            return E_FAIL;    UINT cbDataIn = dwSizeToRead;    if( cbDataIn > m_ck.cksize )
            cbDataIn = m_ck.cksize;    m_ck.cksize -= cbDataIn;    for( DWORD cT = 0; cT < cbDataIn; cT++ ) {
            // Copy the bytes from the io to the buffer.
            if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead ) {
                if( 0 != mmioAdvance( m_hmmio, &mmioinfoIn, MMIO_READ ) )
                    return E_FAIL;            if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
                    return E_FAIL;
            }
            // Actual copy.
            *((BYTE *)pBuffer + cT) = *((BYTE *)mmioinfoIn.pchNext);
            mmioinfoIn.pchNext++;
        }    if( 0 != mmioSetInfo( m_hmmio, &mmioinfoIn, 0 ) )
            return E_FAIL;    if( pdwSizeRead != NULL )
            *pdwSizeRead = cbDataIn;    return S_OK;
    }HRESULT CWaveFile::Close()
    {
        if( flag_ == WAVEFILE_READ ) {
            mmioClose( m_hmmio, 0 );
            m_hmmio = NULL;
            SAFE_DELETE_ARRAY( m_pResourceBuffer );
        } else {
            m_mmioinfoOut.dwFlags |= MMIO_DIRTY;        if( m_hmmio == NULL )
                return CO_E_NOTINITIALIZED;        if( 0 != mmioSetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
                return E_FAIL;        // Ascend the output file out of the 'data' chunk -- this will cause
            // the chunk size of the 'data' chunk to be written.
            if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
                return E_FAIL;        // Do this here instead...
            if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
                return E_FAIL;        mmioSeek( m_hmmio, 0, SEEK_SET );        if( 0 != (INT)mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) )
                return E_FAIL;        m_ck.ckid = mmioFOURCC('f', 'a', 'c', 't');        if( 0 == mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) ) {
                DWORD dwSamples = 0;
                mmioWrite( m_hmmio, (HPSTR)&dwSamples, sizeof(DWORD) );
                mmioAscend( m_hmmio, &m_ck, 0 );
            }        // Ascend the output file out of the 'RIFF' chunk -- this will cause
            // the chunk size of the 'RIFF' chunk to be written.
            if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
                return E_FAIL;        mmioClose( m_hmmio, 0 );
            m_hmmio = NULL;
        }    return S_OK;
    }HRESULT CWaveFile::Write( UINT nSizeToWrite, BYTE *pbSrcData, UINT *pnSizeWrote )
    {
        UINT cT;    if( m_hmmio == NULL )
            return CO_E_NOTINITIALIZED;    if( pnSizeWrote == NULL || pbSrcData == NULL )
            return E_INVALIDARG;    *pnSizeWrote = 0;    for( cT = 0; cT < nSizeToWrite; cT++ ) {
            if( m_mmioinfoOut.pchNext == m_mmioinfoOut.pchEndWrite ) {
                m_mmioinfoOut.dwFlags |= MMIO_DIRTY;            if( 0 != mmioAdvance( m_hmmio, &m_mmioinfoOut, MMIO_WRITE ) )
                    return E_FAIL;
            }        *((BYTE *)m_mmioinfoOut.pchNext) = *((BYTE *)pbSrcData + cT);
            (BYTE *)m_mmioinfoOut.pchNext++;        (*pnSizeWrote)++;
        }
        return S_OK;
    }