ReactOS 0.4.15-dev-7934-g1dc8d80
mixer.c File Reference
#include "dsound_private.h"
Include dependency graph for mixer.c:

Go to the source code of this file.

Functions

void DSOUND_RecalcVolPan (PDSVOLUMEPAN volpan)
 
void DSOUND_AmpFactorToVolPan (PDSVOLUMEPAN volpan)
 
DWORD DSOUND_bufpos_to_mixpos (const DirectSoundDevice *device, DWORD pos)
 
DWORD DSOUND_secpos_to_bufpos (const IDirectSoundBufferImpl *dsb, DWORD secpos, DWORD secmixpos, DWORD *overshot)
 
static DWORD DSOUND_bufpos_to_secpos (const IDirectSoundBufferImpl *dsb, DWORD bufpos)
 
static void DSOUND_RecalcFreqAcc (IDirectSoundBufferImpl *dsb)
 
void DSOUND_RecalcFormat (IDirectSoundBufferImpl *dsb)
 
void DSOUND_CheckEvent (const IDirectSoundBufferImpl *dsb, DWORD playpos, int len)
 
static void cp_fields (const IDirectSoundBufferImpl *dsb, const BYTE *ibuf, BYTE *obuf, UINT istride, UINT ostride, UINT count, UINT freqAcc, UINT adj)
 
static DWORD DSOUND_BufPtrDiff (DWORD buflen, DWORD ptr1, DWORD ptr2)
 
void DSOUND_MixToTemporary (const IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD len, BOOL inmixer)
 
static LPBYTE DSOUND_MixerVol (const IDirectSoundBufferImpl *dsb, INT len)
 
static DWORD DSOUND_MixInBuffer (IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD fraglen)
 
static DWORD DSOUND_MixOne (IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD mixlen)
 
static DWORD DSOUND_MixToPrimary (const DirectSoundDevice *device, DWORD writepos, DWORD mixlen, BOOL recover, BOOL *all_stopped)
 
static void DSOUND_WaveQueue (DirectSoundDevice *device, BOOL force)
 
static void DSOUND_PerformMix (DirectSoundDevice *device)
 
void CALLBACK DSOUND_timer (UINT timerID, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
 
void CALLBACK DSOUND_callback (HWAVEOUT hwo, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
 

Function Documentation

◆ cp_fields()

static void cp_fields ( const IDirectSoundBufferImpl dsb,
const BYTE ibuf,
BYTE obuf,
UINT  istride,
UINT  ostride,
UINT  count,
UINT  freqAcc,
UINT  adj 
)
inlinestatic

Copy a single frame from the given input buffer to the given output buffer. Translate 8 <-> 16 bits and mono <-> stereo

Definition at line 271 of file mixer.c.

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}
#define WARN(fmt,...)
Definition: debug.h:112
GLuint GLuint GLsizei count
Definition: gl.h:1545
static char obuf[100]
Definition: i386-dis.c:1281
static DWORD DWORD istep
Definition: cursoricon.c:1638
bitsconvertfunc convert
DirectSoundDevice * device
WORD nChannels
Definition: mmreg.h:79
WORD wBitsPerSample
Definition: mmreg.h:83
Definition: devices.h:37
int32_t INT
Definition: typedefs.h:58

Referenced by DSOUND_MixToTemporary().

◆ DSOUND_AmpFactorToVolPan()

void DSOUND_AmpFactorToVolPan ( PDSVOLUMEPAN  volpan)

Definition at line 46 of file mixer.c.

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}
GLdouble GLdouble right
Definition: glext.h:10859
GLint left
Definition: glext.h:7726
#define log(outFile, fmt,...)
Definition: util.h:15
#define TRACE(s)
Definition: solgame.cpp:4
DWORD dwTotalRightAmpFactor
Definition: dsdriver.h:106
DWORD dwVolAmpFactor
Definition: dsdriver.h:108
LONG lVolume
Definition: dsdriver.h:107
DWORD dwTotalLeftAmpFactor
Definition: dsdriver.h:105

Referenced by PrimaryBufferImpl_GetPan(), PrimaryBufferImpl_GetVolume(), PrimaryBufferImpl_SetPan(), and PrimaryBufferImpl_SetVolume().

◆ DSOUND_bufpos_to_mixpos()

DWORD DSOUND_bufpos_to_mixpos ( const DirectSoundDevice device,
DWORD  pos 
)

Convert a primary buffer position to a pointer position for device->mix_buffer device: DirectSoundDevice for which to calculate pos: Primary buffer position to converts Returns: Offset for mix_buffer

Definition at line 84 of file mixer.c.

85{
86 DWORD ret = pos * 32 / device->pwfx->wBitsPerSample;
87 if (device->pwfx->wBitsPerSample == 32)
88 ret *= 2;
89 return ret;
90}
unsigned long DWORD
Definition: ntddk_ex.h:95
int ret

Referenced by DSOUND_MixInBuffer(), DSOUND_PerformMix(), DSOUND_PrimaryOpen(), and primarybuffer_SetFormat().

◆ DSOUND_bufpos_to_secpos()

static DWORD DSOUND_bufpos_to_secpos ( const IDirectSoundBufferImpl dsb,
DWORD  bufpos 
)
static

Convert a resampled pointer that fits for primary to a 'native' sample pointer freqAccNext is used here rather than freqAcc: In case the app wants to fill up to the play position it won't overwrite it

Definition at line 125 of file mixer.c.

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}
#define DSOUND_FREQSHIFT
#define DWORD
Definition: nt_native.h:44
PWAVEFORMATEX pwfx
WORD nBlockAlign
Definition: mmreg.h:82
uint64_t DWORD64
Definition: typedefs.h:67

Referenced by DSOUND_MixInBuffer().

◆ DSOUND_BufPtrDiff()

static DWORD DSOUND_BufPtrDiff ( DWORD  buflen,
DWORD  ptr1,
DWORD  ptr2 
)
inlinestatic

Calculate the distance between two buffer offsets, taking wraparound into account.

Definition at line 308 of file mixer.c.

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}
#define assert(x)
Definition: debug.h:53

Referenced by DSOUND_MixInBuffer(), DSOUND_MixOne(), and DSOUND_PerformMix().

◆ DSOUND_callback()

void CALLBACK DSOUND_callback ( HWAVEOUT  hwo,
UINT  msg,
DWORD_PTR  dwUser,
DWORD_PTR  dw1,
DWORD_PTR  dw2 
)

Definition at line 1011 of file mixer.c.

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}
#define msg(x)
Definition: auth_time.c:54
#define ERR(fmt,...)
Definition: debug.h:110
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:455
#define MM_WOM_CLOSE
Definition: mmsystem.h:57
#define MM_WOM_OPEN
Definition: mmsystem.h:56
#define MM_WOM_DONE
Definition: mmsystem.h:58
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)

Referenced by DSOUND_ReopenDevice().

◆ DSOUND_CheckEvent()

void DSOUND_CheckEvent ( const IDirectSoundBufferImpl dsb,
DWORD  playpos,
int  len 
)

Check for application callback requests for when the play position reaches certain points.

The offsets that will be triggered will be those between the recorded "last played" position for the buffer (i.e. dsb->playpos) and "len" bytes beyond that position.

Definition at line 221 of file mixer.c.

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}
#define DSBPN_OFFSETSTOP
Definition: dsound.h:876
#define STATE_STOPPED
struct _cl_event * event
Definition: glext.h:7739
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
LPDSBPOSITIONNOTIFY notifies
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:733

Referenced by DSOUND_MixInBuffer(), DSOUND_MixToPrimary(), and IDirectSoundBufferImpl_Stop().

◆ DSOUND_MixerVol()

static LPBYTE DSOUND_MixerVol ( const IDirectSoundBufferImpl dsb,
INT  len 
)
static

Apply volume to the given soundbuffer from (primary) position writepos and length len Returns: NULL if no volume needs to be applied or else a memory handle that holds 'len' volume adjusted buffer

Definition at line 409 of file mixer.c.

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}
signed short INT16
#define FIXME(fmt,...)
Definition: debug.h:111
#define NULL
Definition: types.h:112
#define GetProcessHeap()
Definition: compat.h:736
#define HeapAlloc
Definition: compat.h:733
#define HeapReAlloc
Definition: compat.h:734
#define DSBCAPS_CTRLVOLUME
Definition: dsound.h:213
#define DSBCAPS_CTRLPAN
Definition: dsound.h:212
#define DSBCAPS_CTRL3D
Definition: dsound.h:210
if(dx< 0)
Definition: linetemp.h:194
int nChannels
Definition: pcmconverter.c:95
DWORD dwFlags
Definition: dsound.h:289
Definition: mem.c:156
unsigned char * LPBYTE
Definition: typedefs.h:53
unsigned char BYTE
Definition: xxhash.c:193

Referenced by DSOUND_MixInBuffer().

◆ DSOUND_MixInBuffer()

static DWORD DSOUND_MixInBuffer ( IDirectSoundBufferImpl dsb,
DWORD  writepos,
DWORD  fraglen 
)
static

Mix (at most) the given number of bytes into the given position of the device buffer, from the secondary buffer "dsb" (starting at the current mix position for that buffer).

Returns the number of bytes actually mixed into the device buffer. This will match fraglen unless the end of the secondary buffer is reached (and it is not looping).

dsb = the secondary buffer to mix from writepos = position (offset) in device buffer to write at fraglen = number of bytes to mix

Definition at line 499 of file mixer.c.

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}
#define TRUE
Definition: types.h:120
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_MixToTemporary(const IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD len, BOOL inmixer)
Definition: mixer.c:332
static DWORD DSOUND_bufpos_to_secpos(const IDirectSoundBufferImpl *dsb, DWORD bufpos)
Definition: mixer.c:125
DWORD DSOUND_bufpos_to_mixpos(const DirectSoundDevice *device, DWORD pos)
Definition: mixer.c:84
static LPBYTE DSOUND_MixerVol(const IDirectSoundBufferImpl *dsb, INT len)
Definition: mixer.c:409
#define DSBCAPS_CTRLPOSITIONNOTIFY
Definition: dsound.h:215
#define DSBPLAY_LOOPING
Definition: dsound.h:189
#define STATE_STARTING
BOOL todo
Definition: filedlg.c:313

Referenced by DSOUND_MixOne().

◆ DSOUND_MixOne()

static DWORD DSOUND_MixOne ( IDirectSoundBufferImpl dsb,
DWORD  writepos,
DWORD  mixlen 
)
static

Mix some frames from the given secondary buffer "dsb" into the device primary buffer.

dsb = the secondary buffer playpos = the current play position in the device buffer (primary buffer) writepos = the current safe-to-write position in the device buffer mixlen = the maximum number of bytes in the primary buffer to mix, from the current writepos.

Returns: the number of bytes beyond the writepos that were mixed.

Definition at line 579 of file mixer.c.

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}
#define FALSE
Definition: types.h:117
static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD fraglen)
Definition: mixer.c:499

Referenced by DSOUND_MixToPrimary().

◆ DSOUND_MixToPrimary()

static DWORD DSOUND_MixToPrimary ( const DirectSoundDevice device,
DWORD  writepos,
DWORD  mixlen,
BOOL  recover,
BOOL all_stopped 
)
static

For a DirectSoundDevice, go through all the currently playing buffers and mix them in to the device buffer.

writepos = the current safe-to-write position in the primary buffer mixlen = the maximum amount to mix into the primary buffer (beyond the current writepos) recover = true if the sound device may have been reset and the write position in the device buffer changed all_stopped = reports back if all buffers have stopped

Returns: the length beyond the writepos that was mixed to.

Definition at line 663 of file mixer.c.

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}
static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD mixlen)
Definition: mixer.c:579
#define STATE_STOPPING
#define STATE_PLAYING
NTSYSAPI BOOLEAN NTAPI RtlAcquireResourceShared(_In_ PRTL_RESOURCE Resource, _In_ BOOLEAN Wait)
NTSYSAPI VOID NTAPI RtlReleaseResource(_In_ PRTL_RESOURCE Resource)
PIDSDRIVERBUFFER hwbuf

Referenced by DSOUND_PerformMix().

◆ DSOUND_MixToTemporary()

void DSOUND_MixToTemporary ( const IDirectSoundBufferImpl dsb,
DWORD  writepos,
DWORD  len,
BOOL  inmixer 
)

Mix at most the given amount of data into the allocated temporary buffer of the given secondary buffer, starting from the dsb's first currently unsampled frame (writepos), translating frequency (pitch), stereo/mono and bits-per-sample so that it is ideal for the primary buffer. Doesn't perform any mixing - this is a straight copy/convert operation.

dsb = the secondary buffer writepos = Starting position of changed buffer len = number of bytes to resample from writepos

NOTE: writepos + len <= buflen. When called by mixer, MixOne makes sure of this.

Definition at line 332 of file mixer.c.

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}
DWORD DSOUND_secpos_to_bufpos(const IDirectSoundBufferImpl *dsb, DWORD secpos, DWORD secmixpos, DWORD *overshot)
Definition: mixer.c:99
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
GLsizeiptr size
Definition: glext.h:5919
DWORD nSamplesPerSec
Definition: mmreg.h:80

Referenced by DSOUND_Calc3DBuffer(), DSOUND_MixInBuffer(), IDirectSoundBufferImpl_Duplicate(), IDirectSoundBufferImpl_SetFrequency(), IDirectSoundBufferImpl_Unlock(), and primarybuffer_SetFormat().

◆ DSOUND_PerformMix()

static void DSOUND_PerformMix ( DirectSoundDevice device)
static

Perform mixing for a Direct Sound device. That is, go through all the secondary buffers (the sound bites currently playing) and mix them in to the primary buffer (the device buffer).

Definition at line 787 of file mixer.c.

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}
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
#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 DSSCL_WRITEPRIMARY
Definition: dsound.h:250
#define DS_OK
Definition: dsound.h:116
HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device) DECLSPEC_HIDDEN
Definition: primary.c:363
HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device) DECLSPEC_HIDDEN
Definition: primary.c:345
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
rwlock_t lock
Definition: tcpcore.h:0
#define ZeroMemory
Definition: winbase.h:1712

Referenced by DSOUND_timer().

◆ DSOUND_RecalcFormat()

void DSOUND_RecalcFormat ( IDirectSoundBufferImpl dsb)

Recalculate the size for temporary buffer, and new writelead Should be called when one of the following things occur:

  • Primary buffer format is changed
  • This buffer format (frequency) is changed

After this, DSOUND_MixToTemporary(dsb, 0, dsb->buflen) should be called to refill the temporary buffer with data.

Definition at line 162 of file mixer.c.

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}
#define HeapFree(x, y, z)
Definition: compat.h:735
const bitsconvertfunc convertbpp[5][4]
int ds_snd_shadow_maxsize
Definition: dsound_main.c:77
#define WAVE_FORMAT_EXTENSIBLE
Definition: ksmedia.h:651
#define KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
Definition: ksmedia.h:1026
#define WAVE_FORMAT_IEEE_FLOAT
Definition: mmreg.h:97
#define IsEqualGUID(rguid1, rguid2)
Definition: guiddef.h:147
WAVEFORMATEX Format
Definition: ksmedia.h:638

Referenced by DSOUND_Calc3DBuffer(), IDirectSoundBufferImpl_Create(), IDirectSoundBufferImpl_Duplicate(), IDirectSoundBufferImpl_SetFrequency(), and primarybuffer_SetFormat().

◆ DSOUND_RecalcFreqAcc()

static void DSOUND_RecalcFreqAcc ( IDirectSoundBufferImpl dsb)
static

Move freqAccNext to freqAcc, and find new values for buffer length and freqAccNext

Definition at line 145 of file mixer.c.

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}

Referenced by DSOUND_MixInBuffer(), and DSOUND_RecalcFormat().

◆ DSOUND_RecalcVolPan()

void DSOUND_RecalcVolPan ( PDSVOLUMEPAN  volpan)

Definition at line 27 of file mixer.c.

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}
double pow(double x, double y)
Definition: freeldr.c:112
static const char mbstate_t *static wchar_t const char mbstate_t *static const wchar_t int *static double
Definition: string.c:80
static calc_node_t temp
Definition: rpn_ieee.c:38
uint32_t ULONG
Definition: typedefs.h:59

Referenced by DSOUND_Calc3DBuffer(), IDirectSoundBufferImpl_Create(), IDirectSoundBufferImpl_SetPan(), IDirectSoundBufferImpl_SetVolume(), PrimaryBufferImpl_SetPan(), and PrimaryBufferImpl_SetVolume().

◆ DSOUND_secpos_to_bufpos()

DWORD DSOUND_secpos_to_bufpos ( const IDirectSoundBufferImpl dsb,
DWORD  secpos,
DWORD  secmixpos,
DWORD overshot 
)

This function converts a 'native' sample pointer to a resampled pointer that fits for primary secmixpos is used to decide which freqAcc is needed overshot tells what the 'actual' secpos is now (optional)

Definition at line 99 of file mixer.c.

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}

Referenced by DSOUND_MixToTemporary(), DSOUND_RecalcFormat(), DSOUND_RecalcFreqAcc(), and IDirectSoundBufferImpl_SetCurrentPosition().

◆ DSOUND_timer()

void CALLBACK DSOUND_timer ( UINT  timerID,
UINT  msg,
DWORD_PTR  dwUser,
DWORD_PTR  dw1,
DWORD_PTR  dw2 
)

Definition at line 984 of file mixer.c.

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}
static void DSOUND_PerformMix(DirectSoundDevice *device)
Definition: mixer.c:787
MMRESULT WINAPI timeKillEvent(UINT wID)
Definition: time.c:370
MMRESULT WINAPI timeEndPeriod(UINT wPeriod)
Definition: time.c:446
DirectSoundDevice * DSOUND_renderer[MAXWAVEDRIVERS]
Definition: dsound_main.c:40
#define DS_TIME_RES

Referenced by DirectSoundDevice_Initialize().

◆ DSOUND_WaveQueue()

static void DSOUND_WaveQueue ( DirectSoundDevice device,
BOOL  force 
)
static

Add buffers to the emulated wave device system.

device = The current dsound playback device force = If TRUE, the function will buffer up as many frags as possible, even though and will ignore the actual state of the primary buffer.

Returns: None

Definition at line 725 of file mixer.c.

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}
UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, UINT uSize)
Definition: winmm.c:2341

Referenced by DSOUND_PerformMix().