/* - - - - - - - - */ // // sound.c // // Copyright (C) 1994 Microsoft Corporation. All Rights Reserved. // /* - - - - - - - - */ #define STRICT #include #include #include #include #include "sound.h" #include /* - - - - - - - - */ typedef struct tagSOUND FAR *PSOUND; typedef struct tagSOUND { WAVEHDR header; LPBYTE pbData; DWORD cbLength; LPWAVEFORMATEX lpwfx; HGLOBAL hgData; HWAVEOUT hwave; HWND hwndNotify; } SOUND; typedef struct { FOURCC fccRiff; DWORD cbSize; FOURCC fccWave; } FILEHEADER, *LPFILEHEADER; typedef struct { DWORD dwCKID; DWORD dwSize; } CHUNKHEADER, *LPCHUNKHEADER; #define RIFF_FILE MAKEFOURCC('R','I','F','F') #define RIFF_WAVE MAKEFOURCC('W','A','V','E') #define RIFF_FORMAT MAKEFOURCC('f','m','t',' ') #define RIFF_DATA MAKEFOURCC('d','a','t','a') /* - - - - - - - - */ #ifdef DEBUG #define STATIC #else #define STATIC static #endif typedef CHUNKHEADER UNALIGNED FAR *ULPCHUNKHEADER; typedef WAVEFORMATEX UNALIGNED FAR *ULPWAVEFORMATEX; /* - - - - - - - - */ STATIC MMRESULT NEAR PASCAL soundInitWaveHeader( PSOUND ps) { size_t cbWFX; ULPWAVEFORMATEX pwfx; ULPCHUNKHEADER pckhdr; LPFILEHEADER pfhdr; LPBYTE pbData; DWORD dwFileSize; DWORD dwCurPos; if (ps->cbLength < sizeof(FILEHEADER)) return MMSYSERR_INVALPARAM; pfhdr = (LPFILEHEADER)ps->pbData; if ((pfhdr->fccRiff != RIFF_FILE) || (pfhdr->fccWave != RIFF_WAVE)) return MMSYSERR_NOTSUPPORTED; dwFileSize = pfhdr->cbSize; dwCurPos = sizeof(FILEHEADER); pbData = (LPBYTE)ps->pbData + sizeof(FILEHEADER); if (ps->cbLength < dwFileSize) return MMSYSERR_INVALPARAM; for (;;) { pckhdr = (ULPCHUNKHEADER)pbData; if (pckhdr->dwCKID == RIFF_FORMAT) break; dwCurPos += pckhdr->dwSize + sizeof(CHUNKHEADER); if (dwCurPos >= dwFileSize) return MMSYSERR_INVALPARAM; pbData += pckhdr->dwSize + sizeof(CHUNKHEADER); } pwfx = (ULPWAVEFORMATEX)(pbData + sizeof(CHUNKHEADER)); cbWFX = sizeof(WAVEFORMATEX); if (pwfx->wFormatTag!=WAVE_FORMAT_PCM) { cbWFX += pwfx->cbSize; } if ((ps->lpwfx = (LPWAVEFORMATEX)GlobalAlloc (GMEM_FIXED, cbWFX)) == 0) return MMSYSERR_NOMEM; memcpy ((char *)ps->lpwfx, pwfx, cbWFX); pbData = pbData + ((ULPCHUNKHEADER)pbData)->dwSize + sizeof(CHUNKHEADER); for (;;) { pckhdr = (ULPCHUNKHEADER)pbData; if (pckhdr->dwCKID == RIFF_DATA) break; dwCurPos += pckhdr->dwSize + sizeof(CHUNKHEADER); if (dwCurPos >= dwFileSize) { GlobalFree ((HGLOBAL)ps->lpwfx); ps->lpwfx = NULL; return MMSYSERR_INVALPARAM; } pbData += pckhdr->dwSize + sizeof(CHUNKHEADER); } ps->header.lpData = pbData + sizeof(CHUNKHEADER); ps->header.dwBufferLength = pckhdr->dwSize; ps->header.dwBytesRecorded = 0; ps->header.dwUser = (DWORD_PTR)ps; ps->header.dwFlags = 0; ps->header.dwLoops = 0; ps->header.lpNext = NULL; ps->header.reserved = 0; return MMSYSERR_NOERROR; } /* - - - - - - - - */ STATIC MMRESULT NEAR PASCAL soundLoadFile( LPCTSTR pszSound, HWND hwndNotify, PSOUND ps) { HFILE hf; MMRESULT mmr; if ((hf = HandleToUlong(CreateFile(pszSound,GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL))) != HFILE_ERROR) { ps->cbLength = _llseek(hf, 0L, SEEK_END); _llseek(hf, 0L, SEEK_SET); if (ps->hgData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, ps->cbLength)) { if (ps->pbData = GlobalLock(ps->hgData)) { if (_hread(hf, ps->pbData, ps->cbLength) == (LONG)ps->cbLength) { if (!(mmr = soundInitWaveHeader(ps))) { _lclose(hf); ps->hwndNotify = hwndNotify; return MMSYSERR_NOERROR; } } else mmr = MMSYSERR_ERROR; GlobalUnlock(ps->hgData); } else mmr = MMSYSERR_ERROR; GlobalFree(ps->hgData); } else mmr = MMSYSERR_NOMEM; _lclose(hf); } else mmr = MMSYSERR_ERROR; return mmr; } /* - - - - - - - - */ void FAR PASCAL soundOnDone( HSOUND hs) { PSOUND ps; ps = (PSOUND)hs; waveOutUnprepareHeader(ps->hwave, &ps->header, sizeof(WAVEHDR)); waveOutClose(ps->hwave); ps->hwave = NULL; } /* - - - - - - - - */ MMRESULT FAR PASCAL soundOpen( LPCTSTR pszSound, HWND hwndNotify, PHSOUND phs) { MMRESULT mmr; if (!(*phs = (HSOUND)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(SOUND)))) return MMSYSERR_NOMEM; if (mmr = soundLoadFile(pszSound, hwndNotify, (PSOUND)*phs)) LocalFree((HLOCAL)*phs); return mmr; } /* - - - - - - - - */ MMRESULT FAR PASCAL soundClose( HSOUND hs) { PSOUND ps; MMRESULT mmr; if (mmr = soundStop(hs)) return mmr; ps = (PSOUND)hs; if (ps->lpwfx != NULL) { GlobalFree ((HGLOBAL)ps->lpwfx); ps->lpwfx = NULL; } GlobalUnlock(ps->hgData); GlobalFree(ps->hgData); LocalFree((HLOCAL)hs); return MMSYSERR_NOERROR; } /* - - - - - - - - */ MMRESULT FAR PASCAL soundPlay( HSOUND hs) { PSOUND ps; MMRESULT mmr; if (mmr = soundStop(hs)) return mmr; ps = (PSOUND)hs; if (!(mmr = waveOutOpen(&ps->hwave, WAVE_MAPPER, ps->lpwfx, (DWORD_PTR)ps->hwndNotify, (DWORD_PTR)ps, CALLBACK_WINDOW | WAVE_ALLOWSYNC))) { ps->header.dwFlags &= ~WHDR_DONE; if (!(mmr = waveOutPrepareHeader(ps->hwave, &ps->header, sizeof(WAVEHDR)))) { if (!(mmr = waveOutWrite(ps->hwave, &ps->header, sizeof(WAVEHDR)))) return MMSYSERR_NOERROR; waveOutUnprepareHeader(ps->hwave, &ps->header, sizeof(WAVEHDR)); } waveOutClose(ps->hwave); ps->hwave = NULL; } return mmr; } /* - - - - - - - - */ MMRESULT FAR PASCAL soundStop( HSOUND hs) { PSOUND ps; MSG msg; ps = (PSOUND)hs; if (ps->hwave) waveOutReset(ps->hwave); if (IsWindow(ps->hwndNotify)) while (PeekMessage(&msg, ps->hwndNotify, MM_WOM_OPEN, MM_WOM_DONE, PM_REMOVE)) { DispatchMessage(&msg); } return MMSYSERR_NOERROR; } /* - - - - - - - - */