VC++ 中WAV音频文件操作

时间:2021-06-19 19:45:49
VC++中WAV音频文件操作的方法,谁能给一个封装好的类了,包括读写操作。
谢谢!

4 个解决方案

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

#4


引用 1 楼 china_jeffery 的回复:
头文件:
#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]


thanks.

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

#4


引用 1 楼 china_jeffery 的回复:
头文件:
#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]


thanks.