static DWORD DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos, DWORD mixlen, BOOL mustlock, BOOL recover, BOOL *all_stopped) { INT i, len; DWORD minlen = 0; IDirectSoundBufferImpl *dsb; BOOL gotall = TRUE; /* unless we find a running buffer, all have stopped */ *all_stopped = TRUE; TRACE("(%d,%d,%d)\n", writepos, mixlen, recover); for (i = 0; i < device->nrofbuffers; i++) { dsb = device->buffers[i]; TRACE("MixToPrimary for %p, state=%d\n", dsb, dsb->state); if (dsb->buflen && dsb->state && !dsb->hwbuf) { TRACE("Checking %p, mixlen=%d\n", dsb, mixlen); if (!RtlAcquireResourceShared(&dsb->lock, mustlock)) { gotall = FALSE; continue; } /* if buffer is stopping it is stopped now */ if (dsb->state == STATE_STOPPING) { dsb->state = STATE_STOPPED; DSOUND_CheckEvent(dsb, 0, 0); } else if (dsb->state != STATE_STOPPED) { /* if recovering, reset the mix position */ if ((dsb->state == STATE_STARTING) || recover) { dsb->primary_mixpos = writepos; } /* if the buffer was starting, it must be playing now */ if (dsb->state == STATE_STARTING) dsb->state = STATE_PLAYING; /* mix next buffer into the main buffer */ len = DSOUND_MixOne(dsb, writepos, mixlen); if (!minlen) minlen = len; /* record the minimum length mixed from all buffers */ /* we only want to return the length which *all* buffers have mixed */ else if (len) minlen = (len < minlen) ? len : minlen; *all_stopped = FALSE; } RtlReleaseResource(&dsb->lock); } } TRACE("Mixed at least %d from all buffers\n", minlen); if (!gotall) return 0; return minlen; }
/** * 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 */ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD fraglen) { INT len = fraglen; BYTE *ibuf, *volbuf; DWORD oldpos, mixbufpos; TRACE("sec_mixpos=%d/%d\n", dsb->sec_mixpos, dsb->buflen); TRACE("(%p,%d,%d)\n",dsb,writepos,fraglen); if (len % dsb->device->pwfx->nBlockAlign) { INT nBlockAlign = dsb->device->pwfx->nBlockAlign; ERR("length not a multiple of block size, len = %d, block size = %d\n", len, nBlockAlign); len -= len % nBlockAlign; /* data alignment */ } /* Resample buffer to temporary buffer specifically allocated for this purpose, if needed */ oldpos = dsb->sec_mixpos; DSOUND_MixToTemporary(dsb, len); ibuf = dsb->device->tmp_buffer; /* Apply volume if needed */ volbuf = DSOUND_MixerVol(dsb, len); if (volbuf) ibuf = volbuf; mixbufpos = DSOUND_bufpos_to_mixpos(dsb->device, writepos); /* Now mix the temporary buffer into the devices main buffer */ if ((writepos + len) <= dsb->device->buflen) dsb->device->mixfunction(ibuf, dsb->device->mix_buffer + mixbufpos, len); else { DWORD todo = dsb->device->buflen - writepos; dsb->device->mixfunction(ibuf, dsb->device->mix_buffer + mixbufpos, todo); dsb->device->mixfunction(ibuf + todo, dsb->device->mix_buffer, len - todo); } /* check for notification positions */ if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY && dsb->state != STATE_STARTING) { INT ilen = DSOUND_BufPtrDiff(dsb->buflen, dsb->sec_mixpos, oldpos); DSOUND_CheckEvent(dsb, oldpos, ilen); } /* increase mix position */ dsb->primary_mixpos += len; dsb->primary_mixpos %= dsb->device->buflen; return len; }
static void DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos, DWORD mixlen, BOOL recover, BOOL *all_stopped) { INT i; IDirectSoundBufferImpl *dsb; /* unless we find a running buffer, all have stopped */ *all_stopped = TRUE; TRACE("(%d,%d,%d)\n", writepos, mixlen, recover); for (i = 0; i < device->nrofbuffers; i++) { dsb = device->buffers[i]; TRACE("MixToPrimary for %p, state=%d\n", dsb, dsb->state); if (dsb->buflen && dsb->state) { TRACE("Checking %p, mixlen=%d\n", dsb, mixlen); RtlAcquireResourceShared(&dsb->lock, TRUE); /* if buffer is stopping it is stopped now */ if (dsb->state == STATE_STOPPING) { dsb->state = STATE_STOPPED; DSOUND_CheckEvent(dsb, 0, 0); } else if (dsb->state != STATE_STOPPED) { /* if the buffer was starting, it must be playing now */ if (dsb->state == STATE_STARTING) dsb->state = STATE_PLAYING; /* mix next buffer into the main buffer */ DSOUND_MixOne(dsb, writepos, mixlen); *all_stopped = FALSE; } RtlReleaseResource(&dsb->lock); } } }
/** * 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 */ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD fraglen) { INT len = fraglen; float *ibuf; DWORD oldpos; UINT frames = fraglen / dsb->device->pwfx->nBlockAlign; TRACE("sec_mixpos=%d/%d\n", dsb->sec_mixpos, dsb->buflen); TRACE("(%p,%d,%d)\n",dsb,writepos,fraglen); if (len % dsb->device->pwfx->nBlockAlign) { INT nBlockAlign = dsb->device->pwfx->nBlockAlign; ERR("length not a multiple of block size, len = %d, block size = %d\n", len, nBlockAlign); len -= len % nBlockAlign; /* data alignment */ } /* Resample buffer to temporary buffer specifically allocated for this purpose, if needed */ oldpos = dsb->sec_mixpos; DSOUND_MixToTemporary(dsb, frames); ibuf = dsb->device->tmp_buffer; /* Apply volume if needed */ DSOUND_MixerVol(dsb, frames); mixieee32(ibuf, dsb->device->mix_buffer, frames * dsb->device->pwfx->nChannels); /* check for notification positions */ if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY && dsb->state != STATE_STARTING) { INT ilen = DSOUND_BufPtrDiff(dsb->buflen, dsb->sec_mixpos, oldpos); DSOUND_CheckEvent(dsb, oldpos, ilen); } return len; }
/** * 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 */ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD fraglen) { INT len = fraglen, ilen; BYTE *ibuf = (dsb->tmp_buffer ? dsb->tmp_buffer : dsb->buffer->memory) + dsb->buf_mixpos, *volbuf; DWORD oldpos, mixbufpos; TRACE("buf_mixpos=%d/%d sec_mixpos=%d/%d\n", dsb->buf_mixpos, dsb->tmp_buffer_len, dsb->sec_mixpos, dsb->buflen); TRACE("(%p,%d,%d)\n",dsb,writepos,fraglen); assert(dsb->buf_mixpos + len <= dsb->tmp_buffer_len); if (len % dsb->device->pwfx->nBlockAlign) { INT nBlockAlign = dsb->device->pwfx->nBlockAlign; ERR("length not a multiple of block size, len = %d, block size = %d\n", len, nBlockAlign); len -= len % nBlockAlign; /* data alignment */ } /* Resample buffer to temporary buffer specifically allocated for this purpose, if needed */ DSOUND_MixToTemporary(dsb, dsb->sec_mixpos, DSOUND_bufpos_to_secpos(dsb, dsb->buf_mixpos+len) - dsb->sec_mixpos, TRUE); if (dsb->resampleinmixer) ibuf = dsb->device->tmp_buffer; /* Apply volume if needed */ volbuf = DSOUND_MixerVol(dsb, len); if (volbuf) ibuf = volbuf; mixbufpos = DSOUND_bufpos_to_mixpos(dsb->device, writepos); /* Now mix the temporary buffer into the devices main buffer */ if ((writepos + len) <= dsb->device->buflen) dsb->device->mixfunction(ibuf, dsb->device->mix_buffer + mixbufpos, len); else { DWORD todo = dsb->device->buflen - writepos; dsb->device->mixfunction(ibuf, dsb->device->mix_buffer + mixbufpos, todo); dsb->device->mixfunction(ibuf + todo, dsb->device->mix_buffer, len - todo); } oldpos = dsb->sec_mixpos; dsb->buf_mixpos += len; if (dsb->buf_mixpos >= dsb->tmp_buffer_len) { if (dsb->buf_mixpos > dsb->tmp_buffer_len) ERR("Mixpos (%u) past buflen (%u), capping...\n", dsb->buf_mixpos, dsb->tmp_buffer_len); if (dsb->playflags & DSBPLAY_LOOPING) { dsb->buf_mixpos -= dsb->tmp_buffer_len; } else if (dsb->buf_mixpos >= dsb->tmp_buffer_len) { dsb->buf_mixpos = dsb->sec_mixpos = 0; dsb->state = STATE_STOPPED; } DSOUND_RecalcFreqAcc(dsb); } dsb->sec_mixpos = DSOUND_bufpos_to_secpos(dsb, dsb->buf_mixpos); ilen = DSOUND_BufPtrDiff(dsb->buflen, dsb->sec_mixpos, oldpos); /* check for notification positions */ if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY && dsb->state != STATE_STARTING) { DSOUND_CheckEvent(dsb, oldpos, ilen); } /* increase mix position */ dsb->primary_mixpos += len; if (dsb->primary_mixpos >= dsb->device->buflen) dsb->primary_mixpos -= dsb->device->buflen; return len; }