📄 playsound.c
字号:
TRACE("SoundName='%s' !\n", debugstr_w(wps->pszSound));
/* if resource, grab it */
if ((wps->fdwSound & SND_RESOURCE) == SND_RESOURCE) {
static const WCHAR wszWave[] = {'W','A','V','E',0};
HRSRC hRes;
HGLOBAL hGlob;
if ((hRes = FindResourceW(wps->hMod, wps->pszSound, wszWave)) == 0 ||
(hGlob = LoadResource(wps->hMod, hRes)) == 0)
goto errCleanUp;
if ((data = LockResource(hGlob)) == NULL) {
FreeResource(hGlob);
goto errCleanUp;
}
FreeResource(hGlob);
} else
data = (void*)wps->pszSound;
/* construct an MMIO stream (either in memory, or from a file */
if (wps->fdwSound & SND_MEMORY)
{ /* NOTE: SND_RESOURCE has the SND_MEMORY bit set */
MMIOINFO mminfo;
memset(&mminfo, 0, sizeof(mminfo));
mminfo.fccIOProc = FOURCC_MEM;
mminfo.pchBuffer = (LPSTR)data;
mminfo.cchBuffer = -1; /* FIXME: when a resource, could grab real size */
TRACE("Memory sound %p\n", data);
hmmio = mmioOpenW(NULL, &mminfo, MMIO_READ);
}
else if (wps->fdwSound & SND_ALIAS)
{
hmmio = get_mmioFromProfile(wps->fdwSound, wps->pszSound);
}
else if (wps->fdwSound & SND_FILENAME)
{
hmmio = get_mmioFromFile(wps->pszSound);
}
else
{
if ((hmmio = get_mmioFromProfile(wps->fdwSound | SND_NODEFAULT, wps->pszSound)) == 0)
{
if ((hmmio = get_mmioFromFile(wps->pszSound)) == 0)
{
hmmio = get_mmioFromProfile(wps->fdwSound, wps->pszSound);
}
}
}
if (hmmio == 0) goto errCleanUp;
if (mmioDescend(hmmio, &ckMainRIFF, NULL, 0))
goto errCleanUp;
TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
(LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize);
if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
(ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E')))
goto errCleanUp;
mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK))
goto errCleanUp;
TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
(LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
lpWaveFormat = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
if (mmioRead(hmmio, (HPSTR)lpWaveFormat, mmckInfo.cksize) < sizeof(WAVEFORMAT))
goto errCleanUp;
TRACE("wFormatTag=%04X !\n", lpWaveFormat->wFormatTag);
TRACE("nChannels=%d \n", lpWaveFormat->nChannels);
TRACE("nSamplesPerSec=%ld\n", lpWaveFormat->nSamplesPerSec);
TRACE("nAvgBytesPerSec=%ld\n", lpWaveFormat->nAvgBytesPerSec);
TRACE("nBlockAlign=%d \n", lpWaveFormat->nBlockAlign);
TRACE("wBitsPerSample=%u !\n", lpWaveFormat->wBitsPerSample);
/* move to end of 'fmt ' chunk */
mmioAscend(hmmio, &mmckInfo, 0);
mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK))
goto errCleanUp;
TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n",
(LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
s.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
if (waveOutOpen(&hWave, WAVE_MAPPER, lpWaveFormat, (DWORD)PlaySound_Callback,
(DWORD)&s, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
goto errCleanUp;
/* make it so that 3 buffers per second are needed */
bufsize = (((lpWaveFormat->nAvgBytesPerSec / 3) - 1) / lpWaveFormat->nBlockAlign + 1) *
lpWaveFormat->nBlockAlign;
waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
if (waveOutPrepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
waveOutPrepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR))) {
goto errCleanUp;
}
s.dwEventCount = 1L; /* for first buffer */
index = 0;
do {
left = mmckInfo.cksize;
mmioSeek(hmmio, mmckInfo.dwDataOffset, SEEK_SET);
while (left)
{
if (WaitForSingleObject(WINMM_IData.psStopEvent, 0) == WAIT_OBJECT_0)
{
wps->bLoop = FALSE;
break;
}
count = mmioRead(hmmio, waveHdr[index].lpData, min(bufsize, left));
if (count < 1) break;
left -= count;
waveHdr[index].dwBufferLength = count;
waveHdr[index].dwFlags &= ~WHDR_DONE;
if (waveOutWrite(hWave, &waveHdr[index], sizeof(WAVEHDR)) == MMSYSERR_NOERROR) {
index ^= 1;
PlaySound_WaitDone(&s);
}
else FIXME("Couldn't play header\n");
}
bRet = TRUE;
} while (wps->bLoop);
PlaySound_WaitDone(&s); /* for last buffer */
waveOutReset(hWave);
waveOutUnprepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR));
waveOutUnprepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR));
errCleanUp:
TRACE("Done playing='%s' => %s!\n", debugstr_w(wps->pszSound), bRet ? "ok" : "ko");
CloseHandle(s.hEvent);
HeapFree(GetProcessHeap(), 0, waveHdr);
HeapFree(GetProcessHeap(), 0, lpWaveFormat);
if (hWave) while (waveOutClose(hWave) == WAVERR_STILLPLAYING) Sleep(100);
if (hmmio) mmioClose(hmmio, 0);
PlaySound_Free(wps);
return bRet;
}
static BOOL MULTIMEDIA_PlaySound(const void* pszSound, HMODULE hmod, DWORD fdwSound, BOOL bUnicode)
{
WINE_PLAYSOUND* wps = NULL;
TRACE("pszSound='%p' hmod=%p fdwSound=%08lX\n",
pszSound, hmod, fdwSound);
/* FIXME? I see no difference between SND_NOWAIT and SND_NOSTOP !
* there could be one if several sounds can be played at once...
*/
if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && WINMM_IData.lpPlaySound != NULL)
return FALSE;
/* alloc internal structure, if we need to play something */
if (pszSound && !(fdwSound & SND_PURGE))
{
if (!(wps = PlaySound_Alloc(pszSound, hmod, fdwSound, bUnicode)))
return FALSE;
}
EnterCriticalSection(&WINMM_IData.cs);
/* since several threads can enter PlaySound in parallel, we're not
* sure, at this point, that another thread didn't start a new playsound
*/
while (WINMM_IData.lpPlaySound != NULL)
{
ResetEvent(WINMM_IData.psLastEvent);
/* FIXME: doc says we have to stop all instances of pszSound if it's non
* NULL... as of today, we stop all playing instances */
SetEvent(WINMM_IData.psStopEvent);
LeaveCriticalSection(&WINMM_IData.cs);
WaitForSingleObject(WINMM_IData.psLastEvent, INFINITE);
EnterCriticalSection(&WINMM_IData.cs);
ResetEvent(WINMM_IData.psStopEvent);
}
if (wps) wps->lpNext = WINMM_IData.lpPlaySound;
WINMM_IData.lpPlaySound = wps;
LeaveCriticalSection(&WINMM_IData.cs);
if (!pszSound || (fdwSound & SND_PURGE)) return TRUE;
if (fdwSound & SND_ASYNC)
{
DWORD id;
HANDLE handle;
wps->bLoop = (fdwSound & SND_LOOP) ? TRUE : FALSE;
if ((handle = CreateThread(NULL, 0, proc_PlaySound, wps, 0, &id)) != 0) {
wps->hThread = handle;
SetThreadPriority(handle, THREAD_PRIORITY_TIME_CRITICAL);
return TRUE;
}
}
else return proc_PlaySound(wps);
/* error cases */
PlaySound_Free(wps);
return FALSE;
}
/**************************************************************************
* PlaySoundA [WINMM.@]
*/
BOOL WINAPI PlaySoundA(LPCSTR pszSoundA, HMODULE hmod, DWORD fdwSound)
{
return MULTIMEDIA_PlaySound(pszSoundA, hmod, fdwSound, FALSE);
}
/**************************************************************************
* PlaySoundW [WINMM.@]
*/
BOOL WINAPI PlaySoundW(LPCWSTR pszSoundW, HMODULE hmod, DWORD fdwSound)
{
return MULTIMEDIA_PlaySound(pszSoundW, hmod, fdwSound, TRUE);
}
/**************************************************************************
* sndPlaySoundA [WINMM.@]
*/
BOOL WINAPI sndPlaySoundA(LPCSTR pszSoundA, UINT uFlags)
{
uFlags &= SND_ASYNC|SND_LOOP|SND_MEMORY|SND_NODEFAULT|SND_NOSTOP|SND_SYNC;
return MULTIMEDIA_PlaySound(pszSoundA, 0, uFlags, FALSE);
}
/**************************************************************************
* sndPlaySoundW [WINMM.@]
*/
BOOL WINAPI sndPlaySoundW(LPCWSTR pszSound, UINT uFlags)
{
uFlags &= SND_ASYNC|SND_LOOP|SND_MEMORY|SND_NODEFAULT|SND_NOSTOP|SND_SYNC;
return MULTIMEDIA_PlaySound(pszSound, 0, uFlags, TRUE);
}
/**************************************************************************
* mmsystemGetVersion [WINMM.@]
*/
UINT WINAPI mmsystemGetVersion(void)
{
TRACE("3.10 (Win95?)\n");
return 0x030a;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -