/***************************************************************** * * Copyright (c) 1996 Microsoft Corporation * * File: wave.cpp * Content: Routines for getting waves from resources * Author: Dave Edson; modified by Peter Donnelly * ******************************************************************/ #include <windows.h> #include "wave.h" typedef struct tagWAVEFILE { DWORD cbSize; // Size of file LPWAVEFORMATEX pwfxInfo; // Wave Header LPBYTE pbData; // Wave Bits } WAVEFILE, *LPWAVEFILE; // Function Prototypes BOOL wave_ParseWaveMemory(void *pvRes, WAVEFORMATEX **ppWaveHeader, BYTE **ppbWaveData, DWORD *pcbWaveSize); ///////////////////////////////////////////////////////////////// // // WAVE_LoadResource: Gets a wave file into the memory pointed // to by pWaveFile from a resource. // ///////////////////////////////////////////////////////////////// LPVOID WAVE_LoadResource (int ID, // ID of resource HMODULE hModule, // hInst of app with WAVE LPWAVEFILE pWaveFile) // Points to the struct to fill { HRSRC hResInfo; HGLOBAL hResData; void *pvRes; DWORD dwSize; LPVOID lpMemory; // Find the resource and load into memory if (((hResInfo = FindResource(hModule, MAKEINTRESOURCE(ID), "WAVE")) != NULL) && ((hResData = LoadResource(hModule, hResInfo)) != NULL) && ((pvRes = LockResource(hResData)) != NULL)) { // If we found it, copy the bits from the resource into // our own chunk of memory dwSize = SizeofResource(hModule, hResInfo); lpMemory = malloc (dwSize); memcpy (lpMemory, pvRes, dwSize); UnlockResource(hResData); FreeResource(hResData); // Parse it out if (wave_ParseWaveMemory(lpMemory, &(pWaveFile->pwfxInfo), &(pWaveFile->pbData), &(pWaveFile->cbSize))) { return lpMemory; // OK } } return NULL; } ////////////////////////////////////////////////////////////////// // // wave_ParseWaveMemory // Parses a chunk of memory into the header and samples. // This is done by looking for the "fmt " and "data" // fields in the memory. // ////////////////////////////////////////////////////////////////// BOOL wave_ParseWaveMemory (LPVOID lpChunkOfMemory, // Points to raw ram LPWAVEFORMATEX *lplpWaveHeader, // Points to pointer to header LPBYTE *lplpWaveSamples,// Points to pointer to samples LPDWORD lpcbWaveSize) // Points to size { LPDWORD pdw; LPDWORD pdwEnd; DWORD dwRiff; DWORD dwType; DWORD dwLength; // Set defaults to NULL or zero if (lplpWaveHeader) *lplpWaveHeader = NULL; if (lplpWaveSamples) *lplpWaveSamples = NULL; if (lpcbWaveSize) *lpcbWaveSize = 0; // Set up DWORD pointers to the start of the chunk // of memory. pdw = (DWORD *)lpChunkOfMemory; // Get the type and length of the chunk of memory dwRiff = *pdw++; dwLength = *pdw++; dwType = *pdw++; // Using the mmioFOURCC macro (part of Windows SDK), ensure // that this is a RIFF WAVE chunk of memory if (dwRiff != mmioFOURCC('R', 'I', 'F', 'F')) return FALSE; // not even RIFF if (dwType != mmioFOURCC('W', 'A', 'V', 'E')) return FALSE; // not a WAV // Find the pointer to the end of the chunk of memory pdwEnd = (DWORD *)((BYTE *)pdw + dwLength-4); // Run through the bytes looking for the tags while (pdw < pdwEnd) { dwType = *pdw++; dwLength = *pdw++; switch (dwType) { // Found the format part case mmioFOURCC('f', 'm', 't', ' '): if (lplpWaveHeader && !*lplpWaveHeader) { if (dwLength < sizeof(WAVEFORMAT)) return FALSE; // something's wrong! Not a WAV // Set the lplpWaveHeader to point to this part of // the memory chunk *lplpWaveHeader = (LPWAVEFORMATEX)pdw; // Check to see if the other two items have been // filled out yet (the bits and the size of the // bits). If so, then this chunk of memory has // been parsed out and we can exit if ((!lplpWaveSamples || *lplpWaveSamples) && (!lpcbWaveSize || *lpcbWaveSize)) { return TRUE; } } break; // Found the samples case mmioFOURCC('d', 'a', 't', 'a'): if ((lplpWaveSamples && !*lplpWaveSamples) || (lpcbWaveSize && !*lpcbWaveSize)) { // Point the samples pointer to this part of the // chunk of memory. if (lplpWaveSamples) *lplpWaveSamples = (LPBYTE)pdw; // Set the size of the wave if (lpcbWaveSize) *lpcbWaveSize = dwLength; // Make sure we have our header pointer set up. // If we do, we can exit if (!lplpWaveHeader || *lplpWaveHeader) return TRUE; } break; } // End case // Move the pointer through the chunk of memory pdw = (DWORD *)((BYTE *)pdw + ((dwLength+1)&~1)); } // Failed! If we made it here, we did not get all the pieces // of the wave return FALSE; } // wave_ParseWaveMemory ////////////////////////////////////////////////////////////////// // // LoadWave // Gets the sound data and loads it into a DirectSound // secondary buffer. // // ////////////////////////////////////////////////////////////////// void LoadWave(HINSTANCE hinst, int ResourceID, LPDIRECTSOUND lpds, LPDIRECTSOUNDBUFFER &lpDSB) { // These variables are used in Steps 1 and 2 LPVOID lpWaveData; WAVEFILE WaveFile; DSBUFFERDESC dsbd; // These variables are used in step 3, further down below LPVOID pbData = NULL; LPVOID pbData2 = NULL; DWORD dwLength; DWORD dwLength2; lpWaveData = WAVE_LoadResource (ResourceID, hinst, &WaveFile ); // Step 1: Set up the direct sound buffer. memset(&dsbd, 0, sizeof(DSBUFFERDESC)); dsbd.dwSize = sizeof(DSBUFFERDESC); // We want a buffer that lives on the sound card's memory // (DSBCAPS_STATIC) and can have the pan, volume, and // frequency adjusted (DSBCAPS_CTRLDEFAULT) dsbd.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_STATIC ; // Set up the size and format dsbd.dwBufferBytes = WaveFile.cbSize; dsbd.lpwfxFormat = WaveFile.pwfxInfo; // Must be a PCM format! // Step 2: Create the buffer if (DS_OK != lpds->CreateSoundBuffer(&dsbd, &lpDSB, NULL)) { OutputDebugString("Failed to create sound buffer\n"); return; } // Once this code succeeds, lpDSB will point to a DirectSoundBuffer. // At this point, you can copy blocks of sound data into the buffer, // using the Lock and Unlock interfaces on the DirectSoundBuffer: // Lock down the DirectSound buffer if (DS_OK == lpDSB->Lock (0, // Offset into buffer to start writing WaveFile.cbSize, // Size of wave file to copy in &pbData, // Points to first block of sound data &dwLength, // Length of first block of data &pbData2, // Points to second block of sound data &dwLength2, // Length of second block of data 0L)) // Flags { // Copy first chunk memcpy(pbData, WaveFile.pbData, dwLength); // Copy second chunk if (dwLength2) memcpy(pbData2, WaveFile.pbData+dwLength , dwLength2); // Free up the memory allocated in the WAVE_LoadFile function, since we // have copied it to the buffer free (lpWaveData); // Unlock the buffer if (DS_OK != lpDSB->Unlock(pbData, dwLength, pbData2, dwLength2)) OutputDebugString("Unlock failed"); } else { OutputDebugString("Lock failed"); } } // LoadWave