Waveform Audio[译]

使用波形和辅助音频

播放WAVE资源

你可以使用PlaySound函数来播放一个存储的资源。虽然这些也可以使用sndPlaySound函数,sndPlaySound需要你查找,加载,锁定,解锁和释放资源;PlaySound可以使用一行来办到这些

PlaySound例子

PlaySound(“SoundName”, hInst, SND_RESOURCE | SND_ASYNC);

sndPlaySound的例子

SND_MEMORY标志位表明lpszSoundName参数是一个指向内存中WAVE映象文件。为了包含一个当作资源的WAVE文件在程序中,增加下面的语句到资源文件中

soundName WAVE c:soundsbells.wav

——————————————————————————————————————

下面这个例子演示了如果用播放资源的函数播放WAVE资源。

BOOL PlayResource(LPSTR lpName)
{
    BOOL bRtn;
    LPSTR lpRes;
    HANDLE hResInfo, hRes;

    // Find the WAVE resource.

    hResInfo = FindResource(hInst, lpName, "WAVE");
    if (hResInfo == NULL)
        return FALSE;

    // Load the WAVE resource.

    hRes = LoadResource(hInst, hResInfo);
    if (hRes == NULL)
        return FALSE;

    // Lock the WAVE resource and play it.

    lpRes = LockResource(hRes);
    if (lpRes != NULL) {
        bRtn = sndPlaySound(lpRes, SND_MEMORY | SND_SYNC |
            SND_NODEFAULT);
        UnlockResource(hRes);
    }
    else
        bRtn = 0;

    // Free the WAVE resource and return success or failure.

    FreeResource(hRes);
    return bRtn;
}
<strong><font size="2">使用PCMWAVEFORMAT结构</font></strong>
<font size="2">对于PCM音频数据,使用PCMWAVEFORMAT结构来指定数据格式。接下来的例子演示了怎样来设置</font>
<font size="2">PCMWAVEFORMAT结构对于11.025KHz,8声道和44.1KHz,16位立体声。在设置PCMWAVEFORMAT之后,</font>
<font size="2">例子调用了IsFormatSupported函数来验证PCM波形输出设备是否支持格式。</font>
<pre><font size="2">UINT wReturn;
PCMWAVEFORMAT pcmWaveFormat;

// Set up PCMWAVEFORMAT for 11 kHz 8-bit mono.

pcmWaveFormat.wf.wFormatTag = WAVE_FORMAT_PCM;
pcmWaveFormat.wf.nChannels = 1;
pcmWaveFormat.wf.nSamplesPerSec = 11025L;
pcmWaveFormat.wf.nAvgBytesPerSec = 11025L;
pcmWaveFormat.wf.nBlockAlign = 1;
pcmWaveFormat.wBitsPerSample = 8;

// See if format is supported by any device in system.

wReturn = IsFormatSupported(&amp;pcmWaveFormat, WAVE_MAPPER);

// Report results.

if (wReturn == 0)
     MessageBox(hMainWnd, "11 kHz 8-bit mono is supported.",
       "", MB_ICONINFORMATION);
else if (wReturn == WAVERR_BADFORMAT)
     MessageBox(hMainWnd, "11 kHz 8-bit mono NOT supported.",
       "", MB_ICONINFORMATION);
else
     MessageBox(hMainWnd, "Error opening waveform device.",
       "Error", MB_ICONEXCLAMATION);

// Set up PCMWAVEFORMAT for 44.1 kHz 16-bit stereo.

pcmWaveFormat.wf.wFormatTag = WAVE_FORMAT_PCM;
pcmWaveFormat.wf.nChannels = 2;
pcmWaveFormat.wf.nSamplesPerSec = 44100L;
pcmWaveFormat.wf.nAvgBytesPerSec = 176400L;
pcmWaveFormat.wf.nBlockAlign = 4;
pcmWaveFormat.wBitsPerSample = 16;

// See if format is supported by any device in the system.

wReturn = IsFormatSupported(&amp;pcmWaveFormat, WAVE_MAPPER);

/ Report results.

if (wReturn == 0)
    MessageBox(hMainWnd, "44.1 kHz 16-bit stereo is supported.",
      "", MB_ICONINFORMATION);
else if (wReturn == WAVERR_BADFORMAT)
    MessageBox(hMainWnd, "44.1 kHz 16-bit stereo NOT supported.",
      "", MB_ICONINFORMATION);
else
    MessageBox(hMainWnd, "Error opening waveform device.",
      "Error", MB_ICONEXCLAMATION);
<strong><font size="3">确定非标准的格式支持</font></strong></font>
<font size="2"><font size="2">为了知道一个设备是否支持一种特别的格式,你可以加上WAVE_FORMAT_QUERY标位调用</font></font>
<font size="2"><font size="2">waveOutOpen函数。接下来的例子使用这个技术来确定一个波形音频设备是否支持一个指定的格式。</font></font>
<pre><font size="2">// Determines whether the specified waveform-audio output device
// supports a specified waveform-audio format. Returns
// MMSYSERR_NOERROR if the format is supported, WAVEERR_BADFORMAT if
// the format is not supported, and one of the other MMSYSERR_ error
// codes if there are other errors encountered in opening the
// specified waveform-audio device.

MMRESULT IsFormatSupported(LPWAVEFORMATEX pwfx, UINT uDeviceID)
{
    return (waveOutOpen(
        NULL,                 // ptr can be NULL for query
        uDeviceID,            // the device identifier
        pwfx,                 // defines requested format
        NULL,                 // no callback
        NULL,                 // no instance data
        WAVE_FORMAT_QUERY));  // query only, do not open device
} <br/>用这种技术来确定是否支持非标准格式对于波形音频输入设备同样也适用。仅仅不同的是使用</font>
<font size="2">waveInOpen函数来代替waveOutOpen来查询支持的格式。</font>
<font size="2">为了确定在系统中一个特殊的波形音频数据设备是否被波形音频设备所支持,使用前面的例子。</font>
<font size="3"><strong>写波形音频数据的例子</strong></font>
<div dir="ltr" style="text-align: left"><p><font size="2">下面的例子说明分配所需采取的步骤,设置WAVEHDR结构和写一个数据块到波形音频输出设备中。</font></p><pre><font size="2">// Global variables.

HANDLE hData  = NULL;  // handle of waveform data memory
HPSTR  lpData = NULL;  // pointer to waveform data memory

void WriteWaveData(void)
{
    HWAVEOUT    hWaveOut;
    HGLOBAL     hWaveHdr;
    LPWAVEHDR   lpWaveHdr;
    HMMIO       hmmio;
    UINT        wResult;
    HANDLE      hFormat;
    WAVEFORMAT  *pFormat;
    DWORD       dwDataSize;

    // Open a waveform device for output using window callback.

    if (waveOutOpen((LPHWAVEOUT)&amp;hWaveOut, WAVE_MAPPER,
                    (LPWAVEFORMAT)pFormat,
                    (LONG)hwndApp, 0L, CALLBACK_WINDOW))
    {
        MessageBox(hwndApp,
                   "Failed to open waveform output device.",
                   NULL, MB_OK | MB_ICONEXCLAMATION);
        LocalUnlock(hFormat);
        LocalFree(hFormat);
        mmioClose(hmmio, 0);
        return;
    }

    // Allocate and lock memory for the waveform data.

    hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, dwDataSize );
    if (!hData)
    {
        MessageBox(hwndApp, "Out of memory.",
                   NULL, MB_OK | MB_ICONEXCLAMATION);
        mmioClose(hmmio, 0);
        return;
    }
    if ((lpData = GlobalLock(hData)) == NULL)
    {
        MessageBox(hwndApp, "Failed to lock memory for data chunk.",
                   NULL, MB_OK | MB_ICONEXCLAMATION);
        GlobalFree(hData);
        mmioClose(hmmio, 0);
        return;
    }

    // Read the waveform data subchunk.

    if(mmioRead(hmmio, (HPSTR) lpData, dwDataSize) != (LRESULT)dwDataSize)
    {
        MessageBox(hwndApp, "Failed to read data chunk.",
                   NULL, MB_OK | MB_ICONEXCLAMATION);
        GlobalUnlock(hData);
        GlobalFree(hData);
        mmioClose(hmmio, 0);
        return;
    }

    // Allocate and lock memory for the header.

    hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
        (DWORD) sizeof(WAVEHDR));
    if (hWaveHdr == NULL)
    {
        GlobalUnlock(hData);
        GlobalFree(hData);
        MessageBox(hwndApp, "Not enough memory for header.",
            NULL, MB_OK | MB_ICONEXCLAMATION);
        return;
    }

    lpWaveHdr = (LPWAVEHDR) GlobalLock(hWaveHdr);
    if (lpWaveHdr == NULL)
    {
        GlobalUnlock(hData);
        GlobalFree(hData);
        MessageBox(hwndApp,
            "Failed to lock memory for header.",
            NULL, MB_OK | MB_ICONEXCLAMATION);
        return;
    }

    // After allocation, set up and prepare header.

    lpWaveHdr-&gt;lpData = lpData;
    lpWaveHdr-&gt;dwBufferLength = dwDataSize;
    lpWaveHdr-&gt;dwFlags = 0L;
    lpWaveHdr-&gt;dwLoops = 0L;
    waveOutPrepareHeader(hWaveOut, lpWaveHdr, sizeof(WAVEHDR));

    // Now the data block can be sent to the output device. The
    // waveOutWrite function returns immediately and waveform
    // data is sent to the output device in the background.

    wResult = waveOutWrite(hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
    if (wResult != 0)
    {
        waveOutUnprepareHeader(hWaveOut, lpWaveHdr,
                               sizeof(WAVEHDR));
        GlobalUnlock( hData);
        GlobalFree(hData);
        MessageBox(hwndApp, "Failed to write block to device",
                   NULL, MB_OK | MB_ICONEXCLAMATION);
        return;
    }
} </font>

处理MM_WOM_DONE消息

接下来的例子演示了怎样处理MM_WOM_DONE消息。这个例子假定应用程序不播放多个数据块,所以它可以

在播放单个数据块后关闭输出设备。

// WndProc--Main window procedure.
LRESULT FAR PASCAL WndProc(HWND hWnd, UINT msg, WPARAM wParam,
    LPARAM lParam)
{
switch (msg)
{
    case MM_WOM_DONE:

    // A waveform-audio data block has been played and
    // can now be freed.
    waveOutUnprepareHeader((HWAVEOUT) wParam,
        (LPWAVEHDR) lParam, sizeof(WAVEHDR) );

    // Free hData memory.

    waveOutClose((HWAVEOUT) wParam);
    break;
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}