⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 waveutil.c

📁 Windows Mobile 6 DirectX 2D源码
💻 C
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
/*==========================================================================
 *
 *
 *  File:       waveutil.c
 *  Content:    Routines for dealing with sounds from resources
 *
 *
 ***************************************************************************/

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>

#include "waveutil.h"

#define dbprintf NKDbgPrintfW


// public objects
struct _tag_SNDDEVICE
{
    ULONG ulDeviceIndex;
};


struct _tag_SNDOBJ
{
    LPCTSTR pszSndName;             // handy for tracing
    PWAVEBUFFER pSndBuffer;          // the underlying sound data
    int iAlloc;                     // number of streams.
    int iCurrent;                   // current stream
    PWAVESTREAM aStreams[1];        // list of streams

}; 
// private objects

struct _tag_WAVEBUFFER
{
    PBYTE           pWaveData;
    DWORD           dwBufferBytes;
    BOOL            fIsResource;
    PWAVEFORMATEX   pFormat;
};

struct _tag_WAVESTREAM 
{
    HWAVEOUT    hwo;
    WAVEHDR     whdr;
};

/////////////////////////////////////////////////////////////
// CWaveBuffer methods
/////////////////////////////////////////////////////////////

void 
CWaveBuffer_Release(PWAVEBUFFER pSndBuffer)
{
    if (pSndBuffer != NULL) {
        if (! pSndBuffer->fIsResource) {
            if (pSndBuffer->pWaveData != NULL) {
                LocalFree(pSndBuffer->pWaveData);
            }
            if (pSndBuffer->pFormat != NULL) {
                LocalFree(pSndBuffer->pFormat);
            }
        }
        LocalFree(pSndBuffer);
    }
}

ULONG 
CWaveBuffer_GetDuration(PWAVEBUFFER pSndBuffer)
{
    return (1000 * pSndBuffer->dwBufferBytes) / pSndBuffer->pFormat->nAvgBytesPerSec;
}

PWAVEBUFFER 
CWaveBuffer_CreateFromResource (HMODULE hModule, LPCTSTR lpName)
{
    HRSRC hResInfo;
    HGLOBAL hResData;
    void *pvRes;
    PWAVEFORMATEX pFormat;
    PBYTE pWaveData;
    DWORD dwBufferBytes;
    PWAVEBUFFER pBuffer = NULL;

    if (    ( (hResInfo = FindResource(hModule, lpName, TEXT("WAV"))) != NULL) &&
            ( (hResData = LoadResource(hModule, hResInfo)) != NULL) &&
            ( (pvRes    = LockResource(hResData)) != NULL) &&
            (  ParseWaveResource(pvRes, &pFormat, &pWaveData, &dwBufferBytes)) &&
            ( (pBuffer = LocalAlloc(LMEM_FIXED, sizeof(*pBuffer))) != NULL))
        {
            pBuffer->dwBufferBytes = dwBufferBytes;
            pBuffer->pFormat = pFormat;
            pBuffer->pWaveData = pWaveData;
            pBuffer->fIsResource = TRUE;
        }

    return pBuffer;
}




///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

BOOL ParseWaveResource(void *pvRes, 
             WAVEFORMATEX **ppWaveHeader, 
             BYTE **ppbWaveData,
             DWORD *pcbWaveSize)
{
    DWORD *pdw;
    DWORD *pdwEnd;
    DWORD dwRiff;
    DWORD dwType;
    DWORD dwLength;

    if (ppWaveHeader)
    *ppWaveHeader = NULL;

    if (ppbWaveData)
    *ppbWaveData = NULL;

    if (pcbWaveSize)
    *pcbWaveSize = 0;

    pdw = (DWORD *)pvRes;
    dwRiff = *pdw++;
    dwLength = *pdw++;
    dwType = *pdw++;

    if (dwRiff != mmioFOURCC('R', 'I', 'F', 'F'))
    goto exit;      // not even RIFF

    if (dwType != mmioFOURCC('W', 'A', 'V', 'E'))
    goto exit;      // not a WAV

    pdwEnd = (DWORD *)((BYTE *)pdw + dwLength-4);

    while (pdw < pdwEnd)
    {
    dwType = *pdw++;
    dwLength = *pdw++;

    switch (dwType)
    {
    case mmioFOURCC('f', 'm', 't', ' '):
        if (ppWaveHeader && !*ppWaveHeader)
        {
        if (dwLength < sizeof(WAVEFORMAT))
            goto exit;      // not a WAV

        *ppWaveHeader = (WAVEFORMATEX *)pdw;

        if ((!ppbWaveData || *ppbWaveData) &&
            (!pcbWaveSize || *pcbWaveSize))
        {
            return TRUE;
        }
        }
        break;

    case mmioFOURCC('d', 'a', 't', 'a'):
        if ((ppbWaveData && !*ppbWaveData) ||
        (pcbWaveSize && !*pcbWaveSize))
        {
        if (ppbWaveData)
            *ppbWaveData = (LPBYTE)pdw;

        if (pcbWaveSize)
            *pcbWaveSize = dwLength;

        if (!ppWaveHeader || *ppWaveHeader)
            return TRUE;
        }
        break;
    }

    pdw = (DWORD *)((BYTE *)pdw + ((dwLength+1)&~1));
    }

exit:
    return FALSE;
}


PWAVESTREAM CWaveStream_Create(ULONG ulDeviceIndex, PWAVEBUFFER pSndBuffer, BOOL fLooping)
{
    MMRESULT mr;

    PWAVESTREAM pStream = LocalAlloc(LMEM_FIXED, sizeof(*pStream));
    if (pStream != NULL) {
        memset(&pStream->whdr, 0, sizeof(WAVEHDR));
        pStream->whdr.dwBufferLength = pSndBuffer->dwBufferBytes;
        pStream->whdr.lpData = pSndBuffer->pWaveData;
        if (fLooping) {
            pStream->whdr.dwFlags |=  (WHDR_BEGINLOOP | WHDR_ENDLOOP);
        }
        mr = waveOutOpen(&pStream->hwo, ulDeviceIndex, pSndBuffer->pFormat, 0, 0, CALLBACK_NULL);
        if (mr == MMSYSERR_NOERROR) {
            mr = waveOutPrepareHeader(pStream->hwo, &pStream->whdr, sizeof(WAVEHDR));
            if (mr != MMSYSERR_NOERROR) {
                dbprintf (TEXT("CWaveStream_Create - waveOutPrepareHeader failed, mr = %2d\r\n"), mr);
            }
        }
        else {
            dbprintf (TEXT("CWaveStream_Create - waveOutOpen failed, mr = %2d\r\n"), mr);
        }
    }
    return pStream;
}

BOOL CWaveStream_Play (PWAVESTREAM pWaveStream)
{
    MMRESULT mr;
    mr = waveOutWrite(pWaveStream->hwo, &pWaveStream->whdr, sizeof(WAVEHDR));
    if (mr != MMSYSERR_NOERROR) {
        dbprintf (TEXT("CWaveStream_Play - waveOutWrite failed, mr = %2d\r\n"), mr);
    }

    return mr == MMSYSERR_NOERROR;
}

BOOL CWaveStream_Close(PWAVESTREAM pWaveStream)
{   
    MMRESULT mr = MMSYSERR_NOERROR;
    int retries = 0;

    CWaveStream_Stop(pWaveStream);

    while (1) {
        mr = waveOutUnprepareHeader(pWaveStream->hwo, &pWaveStream->whdr, sizeof(WAVEHDR));
        if (mr != MMSYSERR_NOERROR) {
            dbprintf (TEXT("CWaveStream_Close - waveOutUnprepareHeader failed, mr = %2d\r\n"), mr);
        }

        mr = waveOutClose(pWaveStream->hwo);
        if (mr == MMSYSERR_NOERROR) {
            break;
        }
        else {
            dbprintf (TEXT("CWaveStream_Close - waveOutClose failed, mr = %2d, retries = %2d\r\n"), mr, retries);
            if (retries++ > 10) {
                break;
            }
        }
        Sleep(2);
    }

    return mr == MMSYSERR_NOERROR;
}


BOOL CWaveStream_IsPlaying(PWAVESTREAM pWaveStream)
{
    // WHDR_INQUEUE is set on waveOutWrite and is cleared when the buffer is completely done.
    // Note: most drivers set WHDR_DONE set well ahead of WHDR_INQUEUE, while the
    // driver is still operating on the buffer. Furthermore, the wave API rejects buffers
    // that are re-submitted with WHDR_INQUEUE still set.
    return (pWaveStream->whdr.dwFlags & WHDR_INQUEUE) != 0;
}


BOOL CWaveStream_Stop(PWAVESTREAM pWaveStream)
{
    BOOL result = FALSE;
    MMRESULT mr = waveOutReset(pWaveStream->hwo);
    if (mr == MMSYSERR_NOERROR) {
        result = TRUE;
    }
    else {
        dbprintf(TEXT("CWaveStream_Stop: waveOutReset failed, mr=%d\r\n"));
    }
    return result;
}

BOOL CWaveStream_SetRate(PWAVESTREAM pWaveStream, ULONG ulRate)
{
    BOOL result = FALSE;
    MMRESULT mr = waveOutSetPlaybackRate(pWaveStream->hwo, ulRate);
    if (mr == MMSYSERR_NOERROR) {
        result = TRUE;
    }
    else {
        dbprintf(TEXT("CWaveStream_SetRate: waveOutSetPlaybackRate failed, mr=%d\r\n"));
    }
    return result;
}

BOOL CWaveStream_SetPan(PWAVESTREAM pWaveStream, LONG lPan)
{
    MMRESULT mr;
    DWORD dwVolume;
    if (lPan < 0) {
        // -10000 -> set right volume to max, left volume per pan
        DWORD dwLeft = ((10000 - ((DWORD) (-lPan))) * 0xffff) / 10000;
        dwVolume = dwLeft | 0xffff0000;
    }
    else if (lPan > 0) {
        // +10000 -> set left volume to max, right volume per pan
        DWORD dwRight = ((10000 - ((DWORD) ( lPan))) * 0xffff) / 10000;
        dwVolume = (dwRight << 16) | 0xffff;
    }
    else {
        dwVolume = 0xFFFFFFFF;
    }

    mr = waveOutSetVolume(pWaveStream->hwo, dwVolume);
    if (mr != MMSYSERR_NOERROR) {
        dbprintf(TEXT("CWaveStream_SetPan: waveOutSetVolume failed, mr=%d\r\n"));
    }
    return mr == MMSYSERR_NOERROR;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -