source: trunk/src/winmm/playsound.cpp@ 5364

Last change on this file since 5364 was 5364, checked in by sandervl, 24 years ago

ported Wine's (snd)PlaySoundA/W + fixed mmsystemGetVersion

File size: 13.8 KB
Line 
1/* $Id: playsound.cpp,v 1.7 2001-03-24 13:23:48 sandervl Exp $ */
2
3/*
4 * Playsound implementation
5 *
6 * Wine port (winmm\mmsystem.c)
7 *
8 * Copyright 1993 Martin Ayotte
9 * Eric POUECH
10 *
11 * Project Odin Software License can be found in LICENSE.TXT
12 *
13 */
14
15
16/****************************************************************************
17 * Includes *
18 ****************************************************************************/
19
20#include <os2win.h>
21#include <odinwrap.h>
22#include <mmsystem.h>
23#include <heapstring.h>
24#include <misc.h>
25#include <string.h>
26#include <win\debugtools.h>
27
28#define DBG_LOCALLOG DBG_playsound
29#include "dbglocal.h"
30
31ODINDEBUGCHANNEL(WINMM-PLAYSOUND)
32
33
34static HANDLE PlaySound_hThread = 0;
35static HANDLE PlaySound_hPlayEvent = 0;
36static HANDLE PlaySound_hReadyEvent = 0;
37static HANDLE PlaySound_hMiddleEvent = 0;
38static BOOL PlaySound_Result = FALSE;
39static int PlaySound_Stop = FALSE;
40static int PlaySound_Playing = FALSE;
41
42static LPCSTR PlaySound_pszSound = NULL;
43static HMODULE PlaySound_hmod = 0;
44static DWORD PlaySound_fdwSound = 0;
45static int PlaySound_Loop = FALSE;
46static int PlaySound_SearchMode = 0; /* 1 - sndPlaySound search order
47 2 - PlaySound order */
48
49static HMMIO get_mmioFromFile(LPCSTR lpszName)
50{
51 return mmioOpenA((LPSTR)lpszName, NULL,
52 MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
53}
54
55static HMMIO get_mmioFromProfile(UINT uFlags, LPCSTR lpszName)
56{
57 char str[128];
58 LPSTR ptr;
59 HMMIO hmmio;
60
61 TRACE("searching in SystemSound List !\n");
62 GetProfileStringA("Sounds", (LPSTR)lpszName, "", str, sizeof(str));
63 if (strlen(str) == 0) {
64 if (uFlags & SND_NODEFAULT) return 0;
65 GetProfileStringA("Sounds", "Default", "", str, sizeof(str));
66 if (strlen(str) == 0) return 0;
67 }
68 if ((ptr = (LPSTR)strchr(str, ',')) != NULL) *ptr = '\0';
69 hmmio = get_mmioFromFile(str);
70 if (hmmio == 0) {
71 WARN("can't find SystemSound='%s' !\n", str);
72 return 0;
73 }
74 return hmmio;
75}
76
77struct playsound_data {
78 HANDLE hEvent;
79 DWORD dwEventCount;
80};
81
82static void CALLBACK PlaySound_Callback(HWAVEOUT hwo, UINT uMsg,
83 DWORD dwInstance,
84 DWORD dwParam1, DWORD dwParam2)
85{
86 struct playsound_data* s = (struct playsound_data*)dwInstance;
87
88 switch (uMsg) {
89 case WOM_OPEN:
90 case WOM_CLOSE:
91 break;
92 case WOM_DONE:
93 InterlockedIncrement((LPLONG)&s->dwEventCount);
94 TRACE("Returning waveHdr=%lx\n", dwParam1);
95 SetEvent(s->hEvent);
96 break;
97 default:
98 ERR("Unknown uMsg=%d\n", uMsg);
99 }
100}
101
102static void PlaySound_WaitDone(struct playsound_data* s)
103{
104 for (;;) {
105 ResetEvent(s->hEvent);
106 if (InterlockedDecrement((LPLONG)&s->dwEventCount) >= 0) {
107 break;
108 }
109 InterlockedIncrement((LPLONG)&s->dwEventCount);
110
111 WaitForSingleObject(s->hEvent, INFINITE);
112 }
113}
114
115static BOOL WINAPI proc_PlaySound(LPCSTR lpszSoundName, UINT uFlags)
116{
117 BOOL bRet = FALSE;
118 HMMIO hmmio = 0;
119 MMCKINFO ckMainRIFF;
120 MMCKINFO mmckInfo;
121 LPWAVEFORMATEX lpWaveFormat = NULL;
122 HWAVE hWave = 0;
123 LPWAVEHDR waveHdr = NULL;
124 INT count, bufsize, left, index;
125 struct playsound_data s;
126
127 s.hEvent = 0;
128
129 TRACE("SoundName='%s' uFlags=%04X !\n", lpszSoundName, uFlags);
130 if (lpszSoundName == NULL) {
131 TRACE("Stop !\n");
132 return FALSE;
133 }
134 if (uFlags & SND_MEMORY) {
135 MMIOINFO mminfo;
136 memset(&mminfo, 0, sizeof(mminfo));
137 mminfo.fccIOProc = FOURCC_MEM;
138 mminfo.pchBuffer = (LPSTR)lpszSoundName;
139 mminfo.cchBuffer = -1;
140 TRACE("Memory sound %p\n", lpszSoundName);
141 hmmio = mmioOpenA(NULL, &mminfo, MMIO_READ);
142 } else {
143 hmmio = 0;
144 if (uFlags & SND_ALIAS)
145 if ((hmmio = get_mmioFromProfile(uFlags, lpszSoundName)) == 0)
146 return FALSE;
147
148 if (uFlags & SND_FILENAME)
149 if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0) return FALSE;
150
151 if (PlaySound_SearchMode == 1) {
152 PlaySound_SearchMode = 0;
153 if ((hmmio = get_mmioFromFile(lpszSoundName)) == 0)
154 hmmio = get_mmioFromProfile(uFlags, lpszSoundName);
155 }
156
157 if (PlaySound_SearchMode == 2) {
158 PlaySound_SearchMode = 0;
159 if ((hmmio = get_mmioFromProfile(uFlags | SND_NODEFAULT, lpszSoundName)) == 0)
160 if ((hmmio = get_mmioFromFile(lpszSoundName)) == 0)
161 hmmio = get_mmioFromProfile(uFlags, lpszSoundName);
162 }
163 }
164 if (hmmio == 0) return FALSE;
165
166 if (mmioDescend(hmmio, &ckMainRIFF, NULL, 0))
167 goto errCleanUp;
168
169 TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
170 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize);
171
172 if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
173 (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E')))
174 goto errCleanUp;
175
176 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
177 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK))
178 goto errCleanUp;
179
180 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
181 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
182
183 lpWaveFormat = (WAVEFORMATEX*)HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
184 if (mmioRead(hmmio, (HPSTR)lpWaveFormat, mmckInfo.cksize) < sizeof(WAVEFORMAT))
185 goto errCleanUp;
186
187 TRACE("wFormatTag=%04X !\n", lpWaveFormat->wFormatTag);
188 TRACE("nChannels=%d \n", lpWaveFormat->nChannels);
189 TRACE("nSamplesPerSec=%ld\n", lpWaveFormat->nSamplesPerSec);
190 TRACE("nAvgBytesPerSec=%ld\n", lpWaveFormat->nAvgBytesPerSec);
191 TRACE("nBlockAlign=%d \n", lpWaveFormat->nBlockAlign);
192 TRACE("wBitsPerSample=%u !\n", lpWaveFormat->wBitsPerSample);
193
194 /* move to end of 'fmt ' chunk */
195 mmioAscend(hmmio, &mmckInfo, 0);
196
197 mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
198 if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK))
199 goto errCleanUp;
200
201 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n",
202 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
203
204 s.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
205
206 if (waveOutOpen(&hWave, WAVE_MAPPER, lpWaveFormat, (DWORD)PlaySound_Callback,
207 (DWORD)&s, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
208 goto errCleanUp;
209
210 /* make it so that 3 buffers per second are needed */
211 bufsize = (((lpWaveFormat->nAvgBytesPerSec / 3) - 1) / lpWaveFormat->nBlockAlign + 1) *
212 lpWaveFormat->nBlockAlign;
213 waveHdr = (LPWAVEHDR)HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
214 waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
215 waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
216 waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
217 waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
218 waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
219 waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
220 if (waveOutPrepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
221 waveOutPrepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR))) {
222 goto errCleanUp;
223 }
224
225 do {
226 index = 0;
227 left = mmckInfo.cksize;
228 s.dwEventCount = 1L; /* for first buffer */
229
230 mmioSeek(hmmio, mmckInfo.dwDataOffset, SEEK_SET);
231 while (left) {
232 if (PlaySound_Stop) {
233 PlaySound_Stop = PlaySound_Loop = FALSE;
234 break;
235 }
236 count = mmioRead(hmmio, waveHdr[index].lpData, min(bufsize, left));
237 if (count < 1) break;
238 left -= count;
239 waveHdr[index].dwBufferLength = count;
240 waveHdr[index].dwFlags &= ~WHDR_DONE;
241 waveOutWrite(hWave, &waveHdr[index], sizeof(WAVEHDR));
242 index ^= 1;
243 PlaySound_WaitDone(&s);
244 }
245 bRet = TRUE;
246 } while (PlaySound_Loop);
247
248 PlaySound_WaitDone(&s);
249 waveOutReset(hWave);
250
251 waveOutUnprepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR));
252 waveOutUnprepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR));
253
254errCleanUp:
255 CloseHandle(s.hEvent);
256 HeapFree(GetProcessHeap(), 0, waveHdr);
257 HeapFree(GetProcessHeap(), 0, lpWaveFormat);
258 if (hWave) while (waveOutClose(hWave) == WAVERR_STILLPLAYING) Sleep(100);
259 if (hmmio) mmioClose(hmmio, 0);
260
261 return bRet;
262}
263
264static DWORD WINAPI PlaySound_Thread(LPVOID arg)
265{
266 DWORD res;
267
268 for (;;) {
269 PlaySound_Playing = FALSE;
270 SetEvent(PlaySound_hReadyEvent);
271 res = WaitForSingleObject(PlaySound_hPlayEvent, INFINITE);
272 ResetEvent(PlaySound_hReadyEvent);
273 SetEvent(PlaySound_hMiddleEvent);
274 if (res == WAIT_FAILED) ExitThread(2);
275 if (res != WAIT_OBJECT_0) continue;
276 PlaySound_Playing = TRUE;
277
278 if ((PlaySound_fdwSound & SND_RESOURCE) == SND_RESOURCE) {
279 HRSRC hRES;
280 HGLOBAL hGLOB;
281 void* ptr;
282
283 if ((hRES = FindResourceA(PlaySound_hmod, PlaySound_pszSound, "WAVE")) == 0) {
284 PlaySound_Result = FALSE;
285 continue;
286 }
287 if ((hGLOB = LoadResource(PlaySound_hmod, hRES)) == 0) {
288 PlaySound_Result = FALSE;
289 continue;
290 }
291 if ((ptr = LockResource(hGLOB)) == NULL) {
292 FreeResource(hGLOB);
293 PlaySound_Result = FALSE;
294 continue;
295 }
296 PlaySound_Result = proc_PlaySound((LPCSTR)ptr,
297 ((UINT16)PlaySound_fdwSound ^ SND_RESOURCE) | SND_MEMORY);
298 FreeResource(hGLOB);
299 continue;
300 }
301 PlaySound_Result = proc_PlaySound(PlaySound_pszSound, (UINT16)PlaySound_fdwSound);
302 }
303}
304
305
306/*****************************************************************************
307 * Plays a sound specified by the given filename, resource, or
308 * system event.
309 * Parameters: LPCSTR pszSound
310 * HMODULE hMod
311 * DWORD fdwSound
312 * Variables :
313 * Result :
314 * Remark :
315 * Status :
316 *
317 * Author : Patrick Haller [Tue, 1998/05/05 10:44]
318 *****************************************************************************/
319
320ODINFUNCTION3(BOOL, PlaySoundA,
321 LPCSTR, pszSound,
322 HMODULE, hmod,
323 DWORD, fdwSound)
324{
325 static LPSTR StrDup = NULL;
326
327 TRACE("pszSound='%p' hmod=%04X fdwSound=%08lX\n",
328 pszSound, hmod, fdwSound);
329
330 if (PlaySound_hThread == 0) { /* This is the first time they called us */
331 DWORD id;
332 if ((PlaySound_hReadyEvent = CreateEventA(NULL, TRUE, FALSE, NULL)) == 0)
333 return FALSE;
334 if ((PlaySound_hMiddleEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == 0)
335 return FALSE;
336 if ((PlaySound_hPlayEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == 0)
337 return FALSE;
338 if ((PlaySound_hThread = CreateThread(NULL, 0, PlaySound_Thread, 0, 0, &id)) == 0)
339 return FALSE;
340 }
341
342 /* FIXME? I see no difference between SND_WAIT and SND_NOSTOP ! */
343 if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && PlaySound_Playing)
344 return FALSE;
345
346 /* Trying to stop if playing */
347 if (PlaySound_Playing) PlaySound_Stop = TRUE;
348
349 /* Waiting playing thread to get ready. I think 10 secs is ok & if not then leave*/
350 if (WaitForSingleObject(PlaySound_hReadyEvent, 1000*10) != WAIT_OBJECT_0)
351 return FALSE;
352
353 if (!pszSound || (fdwSound & SND_PURGE))
354 return FALSE; /* We stoped playing so leaving */
355
356 if (PlaySound_SearchMode != 1) PlaySound_SearchMode = 2;
357 if (!(fdwSound & SND_ASYNC)) {
358 if (fdwSound & SND_LOOP)
359 return FALSE;
360 PlaySound_pszSound = pszSound;
361 PlaySound_hmod = hmod;
362 PlaySound_fdwSound = fdwSound;
363 PlaySound_Result = FALSE;
364 SetEvent(PlaySound_hPlayEvent);
365 if (WaitForSingleObject(PlaySound_hMiddleEvent, INFINITE) != WAIT_OBJECT_0)
366 return FALSE;
367 if (WaitForSingleObject(PlaySound_hReadyEvent, INFINITE) != WAIT_OBJECT_0)
368 return FALSE;
369 return PlaySound_Result;
370 } else {
371 PlaySound_hmod = hmod;
372 PlaySound_fdwSound = fdwSound;
373 PlaySound_Result = FALSE;
374 if (StrDup) {
375 HeapFree(GetProcessHeap(), 0, StrDup);
376 StrDup = NULL;
377 }
378 if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) &&
379 !((DWORD)pszSound >> 16)) || !pszSound)) {
380 StrDup = HEAP_strdupA(GetProcessHeap(), 0,pszSound);
381 PlaySound_pszSound = StrDup;
382 } else PlaySound_pszSound = pszSound;
383 PlaySound_Loop = fdwSound & SND_LOOP;
384 SetEvent(PlaySound_hPlayEvent);
385 ResetEvent(PlaySound_hMiddleEvent);
386 return TRUE;
387 }
388 return FALSE;
389}
390
391
392/*****************************************************************************
393 * Plays a sound specified by the given filename, resource, or
394 * system event.
395 * Parameters: LPCSTR pszSound
396 * HMODULE hMod
397 * DWORD fdwSound
398 * Variables :
399 * Result :
400 * Remark :
401 * Status :
402 *
403 * Author : Patrick Haller [Tue, 1998/05/05 10:44]
404 *****************************************************************************/
405
406ODINFUNCTION3(BOOL, PlaySoundW,
407 LPCWSTR, pszSound,
408 HMODULE, hmod,
409 DWORD, fdwSound)
410{
411 LPSTR pszSoundA;
412 BOOL bSound;
413
414 if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) &&
415 !((DWORD)pszSound >> 16)) || !pszSound)) {
416 pszSoundA = HEAP_strdupWtoA(GetProcessHeap(), 0,pszSound);
417 bSound = PlaySoundA(pszSoundA, hmod, fdwSound);
418 HeapFree(GetProcessHeap(), 0, pszSoundA);
419 } else
420 bSound = PlaySoundA((LPCSTR)pszSound, hmod, fdwSound);
421
422 return bSound;
423}
424
425
426/*****************************************************************************
427 * Plays a sound specified by the given filename
428 * Parameters: LPCSTR pszSound
429 * UINT fuSound
430 * Variables :
431 * Result :
432 * Remark :
433 * Status :
434 *
435 * Author : Patrick Haller [Tue, 1998/05/05 10:44]
436 *****************************************************************************/
437
438ODINFUNCTION2(BOOL, sndPlaySoundA,
439 LPCSTR, lpszSoundName,
440 UINT, uFlags)
441{
442 PlaySound_SearchMode = 1;
443 return PlaySoundA(lpszSoundName, 0, uFlags);
444}
445
446
447/*****************************************************************************
448 * Plays a sound specified by the given filename
449 * Parameters: LPCWSTR pszSound
450 * HMODULE hMod
451 * DWORD fdwSound
452 * Variables :
453 * Result :
454 * Remark :
455 * Status :
456 *
457 * Author : Patrick Haller [Tue, 1998/05/05 10:44]
458 *****************************************************************************/
459
460ODINFUNCTION2(BOOL, sndPlaySoundW,
461 LPCWSTR, lpszSoundName,
462 UINT, uFlags)
463{
464 PlaySound_SearchMode = 1;
465 return PlaySoundW(lpszSoundName, 0, uFlags);
466}
467
Note: See TracBrowser for help on using the repository browser.