windows-nt/Source/XPSP1/NT/shell/osshell/control/mmsys/sound.c
2020-09-26 16:20:57 +08:00

265 lines
7 KiB
C

/* - - - - - - - - */
//
// sound.c
//
// Copyright (C) 1994 Microsoft Corporation. All Rights Reserved.
//
/* - - - - - - - - */
#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <mmddk.h>
#include "sound.h"
#include <tchar.h>
/* - - - - - - - - */
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;
}
/* - - - - - - - - */