ReactOS 0.4.15-dev-8419-g7f0e8a3
mixer.c
Go to the documentation of this file.
1/* DirectSound
2 *
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2002 TransGaming Technologies, Inc.
6 * Copyright 2007 Peter Dons Tychsen
7 * Copyright 2007 Maarten Lankhorst
8 * Copyright 2011 Owen Rudge for CodeWeavers
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include "dsound_private.h"
26
28{
29 double temp;
30 TRACE("(%p)\n",volpan);
31
32 TRACE("Vol=%d Pan=%d\n", volpan->lVolume, volpan->lPan);
33 /* the AmpFactors are expressed in 16.16 fixed point */
34 volpan->dwVolAmpFactor = (ULONG) (pow(2.0, volpan->lVolume / 600.0) * 0xffff);
35 /* FIXME: dwPan{Left|Right}AmpFactor */
36
37 /* FIXME: use calculated vol and pan ampfactors */
38 temp = (double) (volpan->lVolume - (volpan->lPan > 0 ? volpan->lPan : 0));
39 volpan->dwTotalLeftAmpFactor = (ULONG) (pow(2.0, temp / 600.0) * 0xffff);
40 temp = (double) (volpan->lVolume + (volpan->lPan < 0 ? volpan->lPan : 0));
41 volpan->dwTotalRightAmpFactor = (ULONG) (pow(2.0, temp / 600.0) * 0xffff);
42
43 TRACE("left = %x, right = %x\n", volpan->dwTotalLeftAmpFactor, volpan->dwTotalRightAmpFactor);
44}
45
47{
48 double left,right;
49 TRACE("(%p)\n",volpan);
50
51 TRACE("left=%x, right=%x\n",volpan->dwTotalLeftAmpFactor,volpan->dwTotalRightAmpFactor);
52 if (volpan->dwTotalLeftAmpFactor==0)
53 left=-10000;
54 else
55 left=600 * log(((double)volpan->dwTotalLeftAmpFactor) / 0xffff) / log(2);
56 if (volpan->dwTotalRightAmpFactor==0)
57 right=-10000;
58 else
59 right=600 * log(((double)volpan->dwTotalRightAmpFactor) / 0xffff) / log(2);
60 if (left<right)
61 {
62 volpan->lVolume=right;
64 }
65 else
66 {
67 volpan->lVolume=left;
69 }
70 if (volpan->lVolume < -10000)
71 volpan->lVolume=-10000;
72 volpan->lPan=right-left;
73 if (volpan->lPan < -10000)
74 volpan->lPan=-10000;
75
76 TRACE("Vol=%d Pan=%d\n", volpan->lVolume, volpan->lPan);
77}
78
85{
86 DWORD ret = pos * 32 / device->pwfx->wBitsPerSample;
87 if (device->pwfx->wBitsPerSample == 32)
88 ret *= 2;
89 return ret;
90}
91
92/* NOTE: Not all secpos have to always be mapped to a bufpos, other way around is always the case
93 * DWORD64 is used here because a single DWORD wouldn't be big enough to fit the freqAcc for big buffers
94 */
99DWORD DSOUND_secpos_to_bufpos(const IDirectSoundBufferImpl *dsb, DWORD secpos, DWORD secmixpos, DWORD* overshot)
100{
101 DWORD64 framelen = secpos / dsb->pwfx->nBlockAlign;
102 DWORD64 freqAdjust = dsb->freqAdjust;
103 DWORD64 acc, freqAcc;
104
105 if (secpos < secmixpos)
106 freqAcc = dsb->freqAccNext;
107 else freqAcc = dsb->freqAcc;
108 acc = (framelen << DSOUND_FREQSHIFT) + (freqAdjust - 1 - freqAcc);
109 acc /= freqAdjust;
110 if (overshot)
111 {
112 DWORD64 oshot = acc * freqAdjust + freqAcc;
113 assert(oshot >= framelen << DSOUND_FREQSHIFT);
114 oshot -= framelen << DSOUND_FREQSHIFT;
115 *overshot = (DWORD)oshot;
116 assert(*overshot < dsb->freqAdjust);
117 }
118 return (DWORD)acc * dsb->device->pwfx->nBlockAlign;
119}
120
126{
127 DWORD oAdv = dsb->device->pwfx->nBlockAlign, iAdv = dsb->pwfx->nBlockAlign, pos;
128 DWORD64 framelen;
129 DWORD64 acc;
130
131 framelen = bufpos/oAdv;
132 acc = framelen * (DWORD64)dsb->freqAdjust + (DWORD64)dsb->freqAccNext;
133 acc = acc >> DSOUND_FREQSHIFT;
134 pos = (DWORD)acc * iAdv;
135 if (pos >= dsb->buflen)
136 /* Because of differences between freqAcc and freqAccNext, this might happen */
137 pos = dsb->buflen - iAdv;
138 TRACE("Converted %d/%d to %d/%d\n", bufpos, dsb->tmp_buffer_len, pos, dsb->buflen);
139 return pos;
140}
141
146{
147 if (!dsb->freqneeded) return;
148 dsb->freqAcc = dsb->freqAccNext;
149 dsb->tmp_buffer_len = DSOUND_secpos_to_bufpos(dsb, dsb->buflen, 0, &dsb->freqAccNext);
150 TRACE("New freqadjust: %04x, new buflen: %d\n", dsb->freqAccNext, dsb->tmp_buffer_len);
151}
152
163{
164 BOOL needremix = TRUE, needresample = (dsb->freq != dsb->device->pwfx->nSamplesPerSec);
165 DWORD bAlign = dsb->pwfx->nBlockAlign, pAlign = dsb->device->pwfx->nBlockAlign;
167 BOOL ieee = FALSE;
168
169 TRACE("(%p)\n",dsb);
170
171 pwfxe = (WAVEFORMATEXTENSIBLE *) dsb->pwfx;
172
175 ieee = TRUE;
176
177 /* calculate the 10ms write lead */
178 dsb->writelead = (dsb->freq / 100) * dsb->pwfx->nBlockAlign;
179
180 if ((dsb->pwfx->wBitsPerSample == dsb->device->pwfx->wBitsPerSample) &&
181 (dsb->pwfx->nChannels == dsb->device->pwfx->nChannels) && !needresample && !ieee)
182 needremix = FALSE;
184 dsb->tmp_buffer = NULL;
185 dsb->max_buffer_len = dsb->freqAcc = dsb->freqAccNext = 0;
186 dsb->freqneeded = needresample;
187
188 if (ieee)
189 dsb->convert = convertbpp[4][dsb->device->pwfx->wBitsPerSample/8 - 1];
190 else
191 dsb->convert = convertbpp[dsb->pwfx->wBitsPerSample/8 - 1][dsb->device->pwfx->wBitsPerSample/8 - 1];
192
193 dsb->resampleinmixer = FALSE;
194
195 if (needremix)
196 {
197 if (needresample)
199 else
200 dsb->tmp_buffer_len = dsb->buflen / bAlign * pAlign;
201 dsb->max_buffer_len = dsb->tmp_buffer_len;
202 if ((dsb->max_buffer_len <= dsb->device->buflen || dsb->max_buffer_len < ds_snd_shadow_maxsize * 1024 * 1024) && ds_snd_shadow_maxsize >= 0)
204 if (dsb->tmp_buffer)
205 FillMemory(dsb->tmp_buffer, dsb->tmp_buffer_len, dsb->device->pwfx->wBitsPerSample == 8 ? 128 : 0);
206 else
207 dsb->resampleinmixer = TRUE;
208 }
209 else dsb->max_buffer_len = dsb->tmp_buffer_len = dsb->buflen;
211}
212
221void DSOUND_CheckEvent(const IDirectSoundBufferImpl *dsb, DWORD playpos, int len)
222{
223 int i;
226 TRACE("(%p,%d)\n",dsb,len);
227
228 if (dsb->nrofnotifies == 0)
229 return;
230
231 TRACE("(%p) buflen = %d, playpos = %d, len = %d\n",
232 dsb, dsb->buflen, playpos, len);
233 for (i = 0; i < dsb->nrofnotifies ; i++) {
234 event = dsb->notifies + i;
235 offset = event->dwOffset;
236 TRACE("checking %d, position %d, event = %p\n",
237 i, offset, event->hEventNotify);
238 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
239 /* OK. [Inside DirectX, p274] */
240 /* Windows does not seem to enforce this, and some apps rely */
241 /* on that, so we can't stop there. */
242 /* */
243 /* This also means we can't sort the entries by offset, */
244 /* because DSBPN_OFFSETSTOP == -1 */
245 if (offset == DSBPN_OFFSETSTOP) {
246 if (dsb->state == STATE_STOPPED) {
247 SetEvent(event->hEventNotify);
248 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
249 }
250 continue;
251 }
252 if ((playpos + len) >= dsb->buflen) {
253 if ((offset < ((playpos + len) % dsb->buflen)) ||
254 (offset >= playpos)) {
255 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
256 SetEvent(event->hEventNotify);
257 }
258 } else {
259 if ((offset >= playpos) && (offset < (playpos + len))) {
260 TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
261 SetEvent(event->hEventNotify);
262 }
263 }
264 }
265}
266
271static inline void cp_fields(const IDirectSoundBufferImpl *dsb, const BYTE *ibuf, BYTE *obuf,
272 UINT istride, UINT ostride, UINT count, UINT freqAcc, UINT adj)
273{
275 INT istep = dsb->pwfx->wBitsPerSample / 8, ostep = device->pwfx->wBitsPerSample / 8;
276
277 if (device->pwfx->nChannels == dsb->pwfx->nChannels ||
278 (device->pwfx->nChannels == 2 && dsb->pwfx->nChannels == 6) ||
279 (device->pwfx->nChannels == 8 && dsb->pwfx->nChannels == 2) ||
280 (device->pwfx->nChannels == 6 && dsb->pwfx->nChannels == 2)) {
281 dsb->convert(ibuf, obuf, istride, ostride, count, freqAcc, adj);
282 if (device->pwfx->nChannels == 2 || dsb->pwfx->nChannels == 2)
283 dsb->convert(ibuf + istep, obuf + ostep, istride, ostride, count, freqAcc, adj);
284 return;
285 }
286
287 if (device->pwfx->nChannels == 1 && dsb->pwfx->nChannels == 2)
288 {
289 dsb->convert(ibuf, obuf, istride, ostride, count, freqAcc, adj);
290 return;
291 }
292
293 if (device->pwfx->nChannels == 2 && dsb->pwfx->nChannels == 1)
294 {
295 dsb->convert(ibuf, obuf, istride, ostride, count, freqAcc, adj);
296 dsb->convert(ibuf, obuf + ostep, istride, ostride, count, freqAcc, adj);
297 return;
298 }
299
300 WARN("Unable to remap channels: device=%u, buffer=%u\n", device->pwfx->nChannels,
301 dsb->pwfx->nChannels);
302}
303
308static inline DWORD DSOUND_BufPtrDiff(DWORD buflen, DWORD ptr1, DWORD ptr2)
309{
310/* If these asserts fail, the problem is not here, but in the underlying code */
311 assert(ptr1 < buflen);
312 assert(ptr2 < buflen);
313 if (ptr1 >= ptr2) {
314 return ptr1 - ptr2;
315 } else {
316 return buflen + ptr1 - ptr2;
317 }
318}
333{
334 INT size;
335 BYTE *ibp, *obp, *obp_begin;
336 INT iAdvance = dsb->pwfx->nBlockAlign;
337 INT oAdvance = dsb->device->pwfx->nBlockAlign;
338 DWORD freqAcc, target_writepos = 0, overshot, maxlen;
339
340 /* We resample only when needed */
341 if ((dsb->tmp_buffer && inmixer) || (!dsb->tmp_buffer && !inmixer) || dsb->resampleinmixer != inmixer)
342 return;
343
344 assert(writepos + len <= dsb->buflen);
345 if (inmixer && writepos + len < dsb->buflen)
346 len += dsb->pwfx->nBlockAlign;
347
348 maxlen = DSOUND_secpos_to_bufpos(dsb, len, 0, NULL);
349
350 ibp = dsb->buffer->memory + writepos;
351 if (!inmixer)
352 obp_begin = dsb->tmp_buffer;
353 else if (dsb->device->tmp_buffer_len < maxlen || !dsb->device->tmp_buffer)
354 {
355 dsb->device->tmp_buffer_len = maxlen;
356 if (dsb->device->tmp_buffer)
357 dsb->device->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0, dsb->device->tmp_buffer, maxlen);
358 else
359 dsb->device->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, maxlen);
360 obp_begin = dsb->device->tmp_buffer;
361 }
362 else
363 obp_begin = dsb->device->tmp_buffer;
364
365 TRACE("(%p, %p)\n", dsb, ibp);
366 size = len / iAdvance;
367
368 /* Check for same sample rate */
369 if (dsb->freq == dsb->device->pwfx->nSamplesPerSec) {
370 TRACE("(%p) Same sample rate %d = primary %d\n", dsb,
371 dsb->freq, dsb->device->pwfx->nSamplesPerSec);
372 obp = obp_begin;
373 if (!inmixer)
374 obp += writepos/iAdvance*oAdvance;
375
376 cp_fields(dsb, ibp, obp, iAdvance, oAdvance, size, 0, 1 << DSOUND_FREQSHIFT);
377 return;
378 }
379
380 /* Mix in different sample rates */
381 TRACE("(%p) Adjusting frequency: %d -> %d\n", dsb, dsb->freq, dsb->device->pwfx->nSamplesPerSec);
382
383 target_writepos = DSOUND_secpos_to_bufpos(dsb, writepos, dsb->sec_mixpos, &freqAcc);
384 overshot = freqAcc >> DSOUND_FREQSHIFT;
385 if (overshot)
386 {
387 if (overshot >= size)
388 return;
389 size -= overshot;
390 writepos += overshot * iAdvance;
391 if (writepos >= dsb->buflen)
392 return;
393 ibp = dsb->buffer->memory + writepos;
394 freqAcc &= (1 << DSOUND_FREQSHIFT) - 1;
395 TRACE("Overshot: %d, freqAcc: %04x\n", overshot, freqAcc);
396 }
397
398 if (!inmixer)
399 obp = obp_begin + target_writepos;
400 else obp = obp_begin;
401
402 /* FIXME: Small problem here when we're overwriting buf_mixpos, it then STILL uses old freqAcc, not sure if it matters or not */
403 cp_fields(dsb, ibp, obp, iAdvance, oAdvance, size, freqAcc, dsb->freqAdjust);
404}
405
410{
411 INT i;
412 BYTE *bpc;
413 INT16 *bps, *mems;
414 DWORD vLeft, vRight;
416 LPBYTE mem = (dsb->tmp_buffer ? dsb->tmp_buffer : dsb->buffer->memory) + dsb->buf_mixpos;
417
418 if (dsb->resampleinmixer)
419 mem = dsb->device->tmp_buffer;
420
421 TRACE("(%p,%d)\n",dsb,len);
422 TRACE("left = %x, right = %x\n", dsb->volpan.dwTotalLeftAmpFactor,
424
425 if ((!(dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || (dsb->volpan.lPan == 0)) &&
426 (!(dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) || (dsb->volpan.lVolume == 0)) &&
427 !(dsb->dsbd.dwFlags & DSBCAPS_CTRL3D))
428 return NULL; /* Nothing to do */
429
430 if (nChannels != 1 && nChannels != 2)
431 {
432 FIXME("There is no support for %d channels\n", nChannels);
433 return NULL;
434 }
435
436 if (dsb->device->pwfx->wBitsPerSample != 8 && dsb->device->pwfx->wBitsPerSample != 16)
437 {
438 FIXME("There is no support for %d bpp\n", dsb->device->pwfx->wBitsPerSample);
439 return NULL;
440 }
441
442 if (dsb->device->tmp_buffer_len < len || !dsb->device->tmp_buffer)
443 {
444 /* If we just resampled in DSOUND_MixToTemporary, we shouldn't need to resize here */
445 assert(!dsb->resampleinmixer);
446 dsb->device->tmp_buffer_len = len;
447 if (dsb->device->tmp_buffer)
449 else
451 }
452
453 bpc = dsb->device->tmp_buffer;
454 bps = (INT16 *)bpc;
455 mems = (INT16 *)mem;
456 vLeft = dsb->volpan.dwTotalLeftAmpFactor;
457 if (nChannels > 1)
458 vRight = dsb->volpan.dwTotalRightAmpFactor;
459 else
460 vRight = vLeft;
461
462 switch (dsb->device->pwfx->wBitsPerSample) {
463 case 8:
464 /* 8-bit WAV is unsigned, but we need to operate */
465 /* on signed data for this to work properly */
466 for (i = 0; i < len-1; i+=2) {
467 *(bpc++) = (((*(mem++) - 128) * vLeft) >> 16) + 128;
468 *(bpc++) = (((*(mem++) - 128) * vRight) >> 16) + 128;
469 }
470 if (len % 2 == 1 && nChannels == 1)
471 *(bpc++) = (((*(mem++) - 128) * vLeft) >> 16) + 128;
472 break;
473 case 16:
474 /* 16-bit WAV is signed -- much better */
475 for (i = 0; i < len-3; i += 4) {
476 *(bps++) = (*(mems++) * vLeft) >> 16;
477 *(bps++) = (*(mems++) * vRight) >> 16;
478 }
479 if (len % 4 == 2 && nChannels == 1)
480 *(bps++) = ((INT)*(mems++) * vLeft) >> 16;
481 break;
482 }
483 return dsb->device->tmp_buffer;
484}
485
500{
501 INT len = fraglen, ilen;
502 BYTE *ibuf = (dsb->tmp_buffer ? dsb->tmp_buffer : dsb->buffer->memory) + dsb->buf_mixpos, *volbuf;
503 DWORD oldpos, mixbufpos;
504
505 TRACE("buf_mixpos=%d/%d sec_mixpos=%d/%d\n", dsb->buf_mixpos, dsb->tmp_buffer_len, dsb->sec_mixpos, dsb->buflen);
506 TRACE("(%p,%d,%d)\n",dsb,writepos,fraglen);
507
508 assert(dsb->buf_mixpos + len <= dsb->tmp_buffer_len);
509
510 if (len % dsb->device->pwfx->nBlockAlign) {
511 INT nBlockAlign = dsb->device->pwfx->nBlockAlign;
512 ERR("length not a multiple of block size, len = %d, block size = %d\n", len, nBlockAlign);
513 len -= len % nBlockAlign; /* data alignment */
514 }
515
516 /* Resample buffer to temporary buffer specifically allocated for this purpose, if needed */
518 if (dsb->resampleinmixer)
519 ibuf = dsb->device->tmp_buffer;
520
521 /* Apply volume if needed */
522 volbuf = DSOUND_MixerVol(dsb, len);
523 if (volbuf)
524 ibuf = volbuf;
525
526 mixbufpos = DSOUND_bufpos_to_mixpos(dsb->device, writepos);
527 /* Now mix the temporary buffer into the devices main buffer */
528 if ((writepos + len) <= dsb->device->buflen)
529 dsb->device->mixfunction(ibuf, dsb->device->mix_buffer + mixbufpos, len);
530 else
531 {
532 DWORD todo = dsb->device->buflen - writepos;
533 dsb->device->mixfunction(ibuf, dsb->device->mix_buffer + mixbufpos, todo);
534 dsb->device->mixfunction(ibuf + todo, dsb->device->mix_buffer, len - todo);
535 }
536
537 oldpos = dsb->sec_mixpos;
538 dsb->buf_mixpos += len;
539
540 if (dsb->buf_mixpos >= dsb->tmp_buffer_len) {
541 if (dsb->buf_mixpos > dsb->tmp_buffer_len)
542 ERR("Mixpos (%u) past buflen (%u), capping...\n", dsb->buf_mixpos, dsb->tmp_buffer_len);
543 if (dsb->playflags & DSBPLAY_LOOPING) {
544 dsb->buf_mixpos -= dsb->tmp_buffer_len;
545 } else if (dsb->buf_mixpos >= dsb->tmp_buffer_len) {
546 dsb->buf_mixpos = dsb->sec_mixpos = 0;
547 dsb->state = STATE_STOPPED;
548 }
550 }
551
553 ilen = DSOUND_BufPtrDiff(dsb->buflen, dsb->sec_mixpos, oldpos);
554 /* check for notification positions */
556 dsb->state != STATE_STARTING) {
557 DSOUND_CheckEvent(dsb, oldpos, ilen);
558 }
559
560 /* increase mix position */
561 dsb->primary_mixpos += len;
562 if (dsb->primary_mixpos >= dsb->device->buflen)
563 dsb->primary_mixpos -= dsb->device->buflen;
564 return len;
565}
566
580{
581 /* The buffer's primary_mixpos may be before or after the device
582 * buffer's mixpos, but both must be ahead of writepos. */
583 DWORD primary_done;
584
585 TRACE("(%p,%d,%d)\n",dsb,writepos,mixlen);
586 TRACE("writepos=%d, buf_mixpos=%d, primary_mixpos=%d, mixlen=%d\n", writepos, dsb->buf_mixpos, dsb->primary_mixpos, mixlen);
587 TRACE("looping=%d, leadin=%d, buflen=%d\n", dsb->playflags, dsb->leadin, dsb->tmp_buffer_len);
588
589 /* If leading in, only mix about 20 ms, and 'skip' mixing the rest, for more fluid pointer advancement */
590 if (dsb->leadin && dsb->state == STATE_STARTING)
591 {
592 if (mixlen > 2 * dsb->device->fraglen)
593 {
594 dsb->primary_mixpos += mixlen - 2 * dsb->device->fraglen;
595 dsb->primary_mixpos %= dsb->device->buflen;
596 }
597 }
598 dsb->leadin = FALSE;
599
600 /* calculate how much pre-buffering has already been done for this buffer */
601 primary_done = DSOUND_BufPtrDiff(dsb->device->buflen, dsb->primary_mixpos, writepos);
602
603 /* sanity */
604 if(mixlen < primary_done)
605 {
606 /* Should *NEVER* happen */
607 ERR("Fatal error. Under/Overflow? primary_done=%d, mixpos=%d/%d (%d/%d), primary_mixpos=%d, writepos=%d, mixlen=%d\n", primary_done,dsb->buf_mixpos,dsb->tmp_buffer_len,dsb->sec_mixpos, dsb->buflen, dsb->primary_mixpos, writepos, mixlen);
608 dsb->primary_mixpos = writepos + mixlen;
609 dsb->primary_mixpos %= dsb->device->buflen;
610 return mixlen;
611 }
612
613 /* take into account already mixed data */
614 mixlen -= primary_done;
615
616 TRACE("primary_done=%d, mixlen (primary) = %i\n", primary_done, mixlen);
617
618 if (!mixlen)
619 return primary_done;
620
621 /* First try to mix to the end of the buffer if possible
622 * Theoretically it would allow for better optimization
623 */
624 if (mixlen + dsb->buf_mixpos >= dsb->tmp_buffer_len)
625 {
626 DWORD newmixed, mixfirst = dsb->tmp_buffer_len - dsb->buf_mixpos;
627 newmixed = DSOUND_MixInBuffer(dsb, dsb->primary_mixpos, mixfirst);
628 mixlen -= newmixed;
629
630 if (dsb->playflags & DSBPLAY_LOOPING)
631 while (newmixed && mixlen)
632 {
633 mixfirst = (dsb->tmp_buffer_len < mixlen ? dsb->tmp_buffer_len : mixlen);
634 newmixed = DSOUND_MixInBuffer(dsb, dsb->primary_mixpos, mixfirst);
635 mixlen -= newmixed;
636 }
637 }
638 else DSOUND_MixInBuffer(dsb, dsb->primary_mixpos, mixlen);
639
640 /* re-calculate the primary done */
641 primary_done = DSOUND_BufPtrDiff(dsb->device->buflen, dsb->primary_mixpos, writepos);
642
643 TRACE("new primary_mixpos=%d, total mixed data=%d\n", dsb->primary_mixpos, primary_done);
644
645 /* Report back the total prebuffered amount for this buffer */
646 return primary_done;
647}
648
663static DWORD DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos, DWORD mixlen, BOOL recover, BOOL *all_stopped)
664{
665 INT i, len;
666 DWORD minlen = 0;
668
669 /* unless we find a running buffer, all have stopped */
670 *all_stopped = TRUE;
671
672 TRACE("(%d,%d,%d)\n", writepos, mixlen, recover);
673 for (i = 0; i < device->nrofbuffers; i++) {
674 dsb = device->buffers[i];
675
676 TRACE("MixToPrimary for %p, state=%d\n", dsb, dsb->state);
677
678 if (dsb->buflen && dsb->state && !dsb->hwbuf) {
679 TRACE("Checking %p, mixlen=%d\n", dsb, mixlen);
681 /* if buffer is stopping it is stopped now */
682 if (dsb->state == STATE_STOPPING) {
683 dsb->state = STATE_STOPPED;
684 DSOUND_CheckEvent(dsb, 0, 0);
685 } else if (dsb->state != STATE_STOPPED) {
686
687 /* if recovering, reset the mix position */
688 if ((dsb->state == STATE_STARTING) || recover) {
689 dsb->primary_mixpos = writepos;
690 }
691
692 /* if the buffer was starting, it must be playing now */
693 if (dsb->state == STATE_STARTING)
694 dsb->state = STATE_PLAYING;
695
696 /* mix next buffer into the main buffer */
697 len = DSOUND_MixOne(dsb, writepos, mixlen);
698
699 if (!minlen) minlen = len;
700
701 /* record the minimum length mixed from all buffers */
702 /* we only want to return the length which *all* buffers have mixed */
703 else if (len) minlen = (len < minlen) ? len : minlen;
704
705 *all_stopped = FALSE;
706 }
708 }
709 }
710
711 TRACE("Mixed at least %d from all buffers\n", minlen);
712 return minlen;
713}
714
726{
727 DWORD prebuf_frags, wave_writepos, wave_fragpos, i;
728 TRACE("(%p)\n", device);
729
730 /* calculate the current wave frag position */
731 wave_fragpos = (device->pwplay + device->pwqueue) % device->helfrags;
732
733 /* calculate the current wave write position */
734 wave_writepos = wave_fragpos * device->fraglen;
735
736 TRACE("wave_fragpos = %i, wave_writepos = %i, pwqueue = %i, prebuf = %i\n",
737 wave_fragpos, wave_writepos, device->pwqueue, device->prebuf);
738
739 if (!force)
740 {
741 /* check remaining prebuffered frags */
742 prebuf_frags = device->mixpos / device->fraglen;
743 if (prebuf_frags == device->helfrags)
744 --prebuf_frags;
745 TRACE("wave_fragpos = %d, mixpos_frags = %d\n", wave_fragpos, prebuf_frags);
746 if (prebuf_frags < wave_fragpos)
747 prebuf_frags += device->helfrags;
748 prebuf_frags -= wave_fragpos;
749 TRACE("wanted prebuf_frags = %d\n", prebuf_frags);
750 }
751 else
752 /* buffer the maximum amount of frags */
753 prebuf_frags = device->prebuf;
754
755 /* limit to the queue we have left */
756 if ((prebuf_frags + device->pwqueue) > device->prebuf)
757 prebuf_frags = device->prebuf - device->pwqueue;
758
759 TRACE("prebuf_frags = %i\n", prebuf_frags);
760
761 /* adjust queue */
762 device->pwqueue += prebuf_frags;
763
764 /* get out of CS when calling the wave system */
765 LeaveCriticalSection(&(device->mixlock));
766 /* **** */
767
768 /* queue up the new buffers */
769 for(i=0; i<prebuf_frags; i++){
770 TRACE("queueing wave buffer %i\n", wave_fragpos);
771 waveOutWrite(device->hwo, &device->pwave[wave_fragpos], sizeof(WAVEHDR));
772 wave_fragpos++;
773 wave_fragpos %= device->helfrags;
774 }
775
776 /* **** */
777 EnterCriticalSection(&(device->mixlock));
778
779 TRACE("queue now = %i\n", device->pwqueue);
780}
781
788{
789 TRACE("(%p)\n", device);
790
791 /* **** */
792 EnterCriticalSection(&(device->mixlock));
793
794 if (device->priolevel != DSSCL_WRITEPRIMARY) {
795 BOOL recover = FALSE, all_stopped = FALSE;
796 DWORD playpos, writepos, writelead, maxq, frag, prebuff_max, prebuff_left, size1, size2, mixplaypos, mixplaypos2;
797 LPVOID buf1, buf2;
798 BOOL lock = (device->hwbuf && !(device->drvdesc.dwFlags & DSDDESC_DONTNEEDPRIMARYLOCK));
799 int nfiller;
800
801 /* the sound of silence */
802 nfiller = device->pwfx->wBitsPerSample == 8 ? 128 : 0;
803
804 /* get the position in the primary buffer */
805 if (DSOUND_PrimaryGetPosition(device, &playpos, &writepos) != 0){
806 LeaveCriticalSection(&(device->mixlock));
807 return;
808 }
809
810 TRACE("primary playpos=%d, writepos=%d, clrpos=%d, mixpos=%d, buflen=%d\n",
811 playpos,writepos,device->playpos,device->mixpos,device->buflen);
812 assert(device->playpos < device->buflen);
813
814 mixplaypos = DSOUND_bufpos_to_mixpos(device, device->playpos);
815 mixplaypos2 = DSOUND_bufpos_to_mixpos(device, playpos);
816
817 /* calc maximum prebuff */
818 prebuff_max = (device->prebuf * device->fraglen);
819 if (!device->hwbuf && playpos + prebuff_max >= device->helfrags * device->fraglen)
820 prebuff_max += device->buflen - device->helfrags * device->fraglen;
821
822 /* check how close we are to an underrun. It occurs when the writepos overtakes the mixpos */
823 prebuff_left = DSOUND_BufPtrDiff(device->buflen, device->mixpos, playpos);
824 writelead = DSOUND_BufPtrDiff(device->buflen, writepos, playpos);
825
826 /* check for underrun. underrun occurs when the write position passes the mix position
827 * also wipe out just-played sound data */
828 if((prebuff_left > prebuff_max) || (device->state == STATE_STOPPED) || (device->state == STATE_STARTING)){
829 if (device->state == STATE_STOPPING || device->state == STATE_PLAYING)
830 WARN("Probable buffer underrun\n");
831 else TRACE("Buffer starting or buffer underrun\n");
832
833 /* recover mixing for all buffers */
834 recover = TRUE;
835
836 /* reset mix position to write position */
837 device->mixpos = writepos;
838
839 ZeroMemory(device->mix_buffer, device->mix_buffer_len);
840 ZeroMemory(device->buffer, device->buflen);
841 } else if (playpos < device->playpos) {
842 buf1 = device->buffer + device->playpos;
843 buf2 = device->buffer;
844 size1 = device->buflen - device->playpos;
845 size2 = playpos;
846 FillMemory(device->mix_buffer + mixplaypos, device->mix_buffer_len - mixplaypos, 0);
847 FillMemory(device->mix_buffer, mixplaypos2, 0);
848 if (lock)
849 IDsDriverBuffer_Lock(device->hwbuf, &buf1, &size1, &buf2, &size2, device->playpos, size1+size2, 0);
850 FillMemory(buf1, size1, nfiller);
851 if (playpos && (!buf2 || !size2))
852 FIXME("%d: (%d, %d)=>(%d, %d) There should be an additional buffer here!!\n", __LINE__, device->playpos, device->mixpos, playpos, writepos);
853 FillMemory(buf2, size2, nfiller);
854 if (lock)
855 IDsDriverBuffer_Unlock(device->hwbuf, buf1, size1, buf2, size2);
856 } else {
857 buf1 = device->buffer + device->playpos;
858 buf2 = NULL;
859 size1 = playpos - device->playpos;
860 size2 = 0;
861 FillMemory(device->mix_buffer + mixplaypos, mixplaypos2 - mixplaypos, 0);
862 if (lock)
863 IDsDriverBuffer_Lock(device->hwbuf, &buf1, &size1, &buf2, &size2, device->playpos, size1+size2, 0);
864 FillMemory(buf1, size1, nfiller);
865 if (buf2 && size2)
866 {
867 FIXME("%d: There should be no additional buffer here!!\n", __LINE__);
868 FillMemory(buf2, size2, nfiller);
869 }
870 if (lock)
871 IDsDriverBuffer_Unlock(device->hwbuf, buf1, size1, buf2, size2);
872 }
873 device->playpos = playpos;
874
875 /* find the maximum we can prebuffer from current write position */
876 maxq = (writelead < prebuff_max) ? (prebuff_max - writelead) : 0;
877
878 TRACE("prebuff_left = %d, prebuff_max = %dx%d=%d, writelead=%d\n",
879 prebuff_left, device->prebuf, device->fraglen, prebuff_max, writelead);
880
881 if (lock)
882 IDsDriverBuffer_Lock(device->hwbuf, &buf1, &size1, &buf2, &size2, writepos, maxq, 0);
883
884 /* do the mixing */
885 frag = DSOUND_MixToPrimary(device, writepos, maxq, recover, &all_stopped);
886
887 if (frag + writepos > device->buflen)
888 {
889 DWORD todo = device->buflen - writepos;
890 device->normfunction(device->mix_buffer + DSOUND_bufpos_to_mixpos(device, writepos), device->buffer + writepos, todo);
891 device->normfunction(device->mix_buffer, device->buffer, frag - todo);
892 }
893 else
894 device->normfunction(device->mix_buffer + DSOUND_bufpos_to_mixpos(device, writepos), device->buffer + writepos, frag);
895
896 /* update the mix position, taking wrap-around into account */
897 device->mixpos = writepos + frag;
898 device->mixpos %= device->buflen;
899
900 if (lock)
901 {
902 DWORD frag2 = (frag > size1 ? frag - size1 : 0);
903 frag -= frag2;
904 if (frag2 > size2)
905 {
906 FIXME("Buffering too much! (%d, %d, %d, %d)\n", maxq, frag, size2, frag2 - size2);
907 frag2 = size2;
908 }
909 IDsDriverBuffer_Unlock(device->hwbuf, buf1, frag, buf2, frag2);
910 }
911
912 /* update prebuff left */
913 prebuff_left = DSOUND_BufPtrDiff(device->buflen, device->mixpos, playpos);
914
915 /* check if have a whole fragment */
916 if (prebuff_left >= device->fraglen){
917
918 /* update the wave queue if using wave system */
919 if (!device->hwbuf)
921
922 /* buffers are full. start playing if applicable */
923 if(device->state == STATE_STARTING){
924 TRACE("started primary buffer\n");
926 WARN("DSOUND_PrimaryPlay failed\n");
927 }
928 else{
929 /* we are playing now */
930 device->state = STATE_PLAYING;
931 }
932 }
933
934 /* buffers are full. start stopping if applicable */
935 if(device->state == STATE_STOPPED){
936 TRACE("restarting primary buffer\n");
938 WARN("DSOUND_PrimaryPlay failed\n");
939 }
940 else{
941 /* start stopping again. as soon as there is no more data, it will stop */
942 device->state = STATE_STOPPING;
943 }
944 }
945 }
946
947 /* if device was stopping, its for sure stopped when all buffers have stopped */
948 else if((all_stopped != FALSE) && (device->state == STATE_STOPPING)){
949 TRACE("All buffers have stopped. Stopping primary buffer\n");
950 device->state = STATE_STOPPED;
951
952 /* stop the primary buffer now */
954 }
955
956 } else {
957
958 /* update the wave queue if using wave system */
959 if (!device->hwbuf)
961 else
962 /* Keep alsa happy, which needs GetPosition called once every 10 ms */
964
965 /* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */
966 if (device->state == STATE_STARTING) {
968 WARN("DSOUND_PrimaryPlay failed\n");
969 else
970 device->state = STATE_PLAYING;
971 }
972 else if (device->state == STATE_STOPPING) {
974 WARN("DSOUND_PrimaryStop failed\n");
975 else
976 device->state = STATE_STOPPED;
977 }
978 }
979
980 LeaveCriticalSection(&(device->mixlock));
981 /* **** */
982}
983
985 DWORD_PTR dw1, DWORD_PTR dw2)
986{
988 DWORD start_time = GetTickCount();
989 DWORD end_time;
990 TRACE("(%d,%d,0x%lx,0x%lx,0x%lx)\n",timerID,msg,dwUser,dw1,dw2);
991 TRACE("entering at %d\n", start_time);
992
993 if (DSOUND_renderer[device->drvdesc.dnDevNode] != device) {
994 ERR("dsound died without killing us?\n");
995 timeKillEvent(timerID);
997 return;
998 }
999
1000 RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
1001
1002 if (device->ref)
1004
1005 RtlReleaseResource(&(device->buffer_list_lock));
1006
1007 end_time = GetTickCount();
1008 TRACE("completed processing at %d, duration = %d\n", end_time, end_time - start_time);
1009}
1010
1011void CALLBACK DSOUND_callback(HWAVEOUT hwo, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
1012{
1014 TRACE("(%p,%x,%lx,%lx,%lx)\n",hwo,msg,dwUser,dw1,dw2);
1015 TRACE("entering at %d, msg=%08x(%s)\n", GetTickCount(), msg,
1016 msg==MM_WOM_DONE ? "MM_WOM_DONE" : msg==MM_WOM_CLOSE ? "MM_WOM_CLOSE" :
1017 msg==MM_WOM_OPEN ? "MM_WOM_OPEN" : "UNKNOWN");
1018
1019 /* check if packet completed from wave driver */
1020 if (msg == MM_WOM_DONE) {
1021
1022 /* **** */
1023 EnterCriticalSection(&(device->mixlock));
1024
1025 TRACE("done playing primary pos=%d\n", device->pwplay * device->fraglen);
1026
1027 /* update playpos */
1028 device->pwplay++;
1029 device->pwplay %= device->helfrags;
1030
1031 /* sanity */
1032 if(device->pwqueue == 0){
1033 ERR("Wave queue corrupted!\n");
1034 }
1035
1036 /* update queue */
1037 device->pwqueue--;
1038
1039 LeaveCriticalSection(&(device->mixlock));
1040 /* **** */
1041 }
1042 TRACE("completed\n");
1043}
signed short INT16
#define msg(x)
Definition: auth_time.c:54
#define FIXME(fmt,...)
Definition: precomp.h:53
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
Definition: mixer.c:162
void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan)
Definition: mixer.c:46
static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD mixlen)
Definition: mixer.c:579
void DSOUND_CheckEvent(const IDirectSoundBufferImpl *dsb, DWORD playpos, int len)
Definition: mixer.c:221
static DWORD DSOUND_BufPtrDiff(DWORD buflen, DWORD ptr1, DWORD ptr2)
Definition: mixer.c:308
static void DSOUND_RecalcFreqAcc(IDirectSoundBufferImpl *dsb)
Definition: mixer.c:145
void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan)
Definition: mixer.c:27
void DSOUND_MixToTemporary(const IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD len, BOOL inmixer)
Definition: mixer.c:332
static void DSOUND_PerformMix(DirectSoundDevice *device)
Definition: mixer.c:787
DWORD DSOUND_secpos_to_bufpos(const IDirectSoundBufferImpl *dsb, DWORD secpos, DWORD secmixpos, DWORD *overshot)
Definition: mixer.c:99
void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
Definition: mixer.c:984
static DWORD DSOUND_bufpos_to_secpos(const IDirectSoundBufferImpl *dsb, DWORD bufpos)
Definition: mixer.c:125
static DWORD DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos, DWORD mixlen, BOOL recover, BOOL *all_stopped)
Definition: mixer.c:663
static void DSOUND_WaveQueue(DirectSoundDevice *device, BOOL force)
Definition: mixer.c:725
DWORD DSOUND_bufpos_to_mixpos(const DirectSoundDevice *device, DWORD pos)
Definition: mixer.c:84
static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD fraglen)
Definition: mixer.c:499
void CALLBACK DSOUND_callback(HWAVEOUT hwo, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
Definition: mixer.c:1011
static void cp_fields(const IDirectSoundBufferImpl *dsb, const BYTE *ibuf, BYTE *obuf, UINT istride, UINT ostride, UINT count, UINT freqAcc, UINT adj)
Definition: mixer.c:271
static LPBYTE DSOUND_MixerVol(const IDirectSoundBufferImpl *dsb, INT len)
Definition: mixer.c:409
#define GetProcessHeap()
Definition: compat.h:736
#define HeapAlloc
Definition: compat.h:733
#define HeapReAlloc
Definition: compat.h:734
#define HeapFree(x, y, z)
Definition: compat.h:735
#define CALLBACK
Definition: compat.h:35
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:455
MMRESULT WINAPI timeKillEvent(UINT wID)
Definition: time.c:370
MMRESULT WINAPI timeEndPeriod(UINT wPeriod)
Definition: time.c:446
#define assert(x)
Definition: debug.h:53
#define IDsDriverBuffer_Unlock(p, a, b, c, d)
Definition: dsdriver.h:197
#define DSDDESC_DONTNEEDPRIMARYLOCK
Definition: dsdriver.h:53
#define IDsDriverBuffer_GetPosition(p, a, b)
Definition: dsdriver.h:202
#define IDsDriverBuffer_Lock(p, a, b, c, d, e, f, g)
Definition: dsdriver.h:196
#define DSBCAPS_CTRLVOLUME
Definition: dsound.h:213
#define DSBCAPS_CTRLPAN
Definition: dsound.h:212
#define DSBPN_OFFSETSTOP
Definition: dsound.h:876
#define DSSCL_WRITEPRIMARY
Definition: dsound.h:250
#define DSBCAPS_CTRLPOSITIONNOTIFY
Definition: dsound.h:215
#define DS_OK
Definition: dsound.h:116
#define DSBCAPS_CTRL3D
Definition: dsound.h:210
#define DSBPLAY_LOOPING
Definition: dsound.h:189
const bitsconvertfunc convertbpp[5][4]
int ds_snd_shadow_maxsize
Definition: dsound_main.c:77
DirectSoundDevice * DSOUND_renderer[MAXWAVEDRIVERS]
Definition: dsound_main.c:40
#define STATE_STOPPING
HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device) DECLSPEC_HIDDEN
Definition: primary.c:363
#define STATE_PLAYING
#define DS_TIME_RES
HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device) DECLSPEC_HIDDEN
Definition: primary.c:345
#define STATE_STARTING
#define STATE_STOPPED
#define DSOUND_FREQSHIFT
HRESULT DSOUND_PrimaryGetPosition(DirectSoundDevice *device, LPDWORD playpos, LPDWORD writepos) DECLSPEC_HIDDEN
Definition: primary.c:402
#define FillMemory(BUF, SIZ, MASK)
Definition: strucsup.c:31
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
double pow(double x, double y)
Definition: freeldr.c:113
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLsizeiptr size
Definition: glext.h:5919
struct _cl_event * event
Definition: glext.h:7739
GLdouble GLdouble right
Definition: glext.h:10859
GLint left
Definition: glext.h:7726
GLenum GLsizei len
Definition: glext.h:6722
GLintptr offset
Definition: glext.h:5920
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
static char obuf[100]
Definition: i386-dis.c:1281
#define WAVE_FORMAT_EXTENSIBLE
Definition: ksmedia.h:651
#define KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
Definition: ksmedia.h:1026
if(dx< 0)
Definition: linetemp.h:194
#define WAVE_FORMAT_IEEE_FLOAT
Definition: mmreg.h:97
#define MM_WOM_CLOSE
Definition: mmsystem.h:57
#define MM_WOM_OPEN
Definition: mmsystem.h:56
#define MM_WOM_DONE
Definition: mmsystem.h:58
BOOL todo
Definition: filedlg.c:313
static const char mbstate_t *static wchar_t const char mbstate_t *static const wchar_t int *static double
Definition: string.c:80
static DWORD DWORD istep
Definition: cursoricon.c:1638
unsigned int UINT
Definition: ndis.h:50
NTSYSAPI BOOLEAN NTAPI RtlAcquireResourceShared(_In_ PRTL_RESOURCE Resource, _In_ BOOLEAN Wait)
NTSYSAPI VOID NTAPI RtlReleaseResource(_In_ PRTL_RESOURCE Resource)
#define DWORD
Definition: nt_native.h:44
int nChannels
Definition: pcmconverter.c:95
#define IsEqualGUID(rguid1, rguid2)
Definition: guiddef.h:147
static calc_node_t temp
Definition: rpn_ieee.c:38
#define log(outFile, fmt,...)
Definition: util.h:15
#define TRACE(s)
Definition: solgame.cpp:4
PWAVEFORMATEX pwfx
bitsconvertfunc convert
PIDSDRIVERBUFFER hwbuf
DirectSoundDevice * device
LPDSBPOSITIONNOTIFY notifies
WAVEFORMATEX Format
Definition: ksmedia.h:638
DWORD dwFlags
Definition: dsound.h:289
DWORD dwTotalRightAmpFactor
Definition: dsdriver.h:106
DWORD dwVolAmpFactor
Definition: dsdriver.h:108
LONG lVolume
Definition: dsdriver.h:107
DWORD dwTotalLeftAmpFactor
Definition: dsdriver.h:105
WORD nBlockAlign
Definition: mmreg.h:82
DWORD nSamplesPerSec
Definition: mmreg.h:80
WORD nChannels
Definition: mmreg.h:79
WORD wBitsPerSample
Definition: mmreg.h:83
Definition: devices.h:37
Definition: mem.c:156
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:733
rwlock_t lock
Definition: tcpcore.h:0
uint32_t DWORD_PTR
Definition: typedefs.h:65
uint64_t DWORD64
Definition: typedefs.h:67
unsigned char * LPBYTE
Definition: typedefs.h:53
int32_t INT
Definition: typedefs.h:58
uint32_t ULONG
Definition: typedefs.h:59
int ret
#define ZeroMemory
Definition: winbase.h:1712
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, UINT uSize)
Definition: winmm.c:2341
unsigned char BYTE
Definition: xxhash.c:193