/** * 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. */ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb) { BOOL needremix = TRUE, needresample = (dsb->freq != dsb->device->pwfx->nSamplesPerSec); DWORD bAlign = dsb->pwfx->nBlockAlign, pAlign = dsb->device->pwfx->nBlockAlign; WAVEFORMATEXTENSIBLE *pwfxe; BOOL ieee = FALSE; TRACE("(%p)\n",dsb); pwfxe = (WAVEFORMATEXTENSIBLE *) dsb->pwfx; if ((pwfxe->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) || ((pwfxe->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) && (IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))) ieee = TRUE; /* calculate the 10ms write lead */ dsb->writelead = (dsb->freq / 100) * dsb->pwfx->nBlockAlign; if ((dsb->pwfx->wBitsPerSample == dsb->device->pwfx->wBitsPerSample) && (dsb->pwfx->nChannels == dsb->device->pwfx->nChannels) && !needresample && !ieee) needremix = FALSE; HeapFree(GetProcessHeap(), 0, dsb->tmp_buffer); dsb->tmp_buffer = NULL; dsb->max_buffer_len = dsb->freqAcc = dsb->freqAccNext = 0; dsb->freqneeded = needresample; if (ieee) dsb->convert = convertbpp[4][dsb->device->pwfx->wBitsPerSample/8 - 1]; else dsb->convert = convertbpp[dsb->pwfx->wBitsPerSample/8 - 1][dsb->device->pwfx->wBitsPerSample/8 - 1]; dsb->resampleinmixer = FALSE; if (needremix) { if (needresample) DSOUND_RecalcFreqAcc(dsb); else dsb->tmp_buffer_len = dsb->buflen / bAlign * pAlign; dsb->max_buffer_len = dsb->tmp_buffer_len; if ((dsb->max_buffer_len <= dsb->device->buflen || dsb->max_buffer_len < ds_snd_shadow_maxsize * 1024 * 1024) && ds_snd_shadow_maxsize >= 0) dsb->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, dsb->max_buffer_len); if (dsb->tmp_buffer) FillMemory(dsb->tmp_buffer, dsb->tmp_buffer_len, dsb->device->pwfx->wBitsPerSample == 8 ? 128 : 0); else dsb->resampleinmixer = TRUE; } else dsb->max_buffer_len = dsb->tmp_buffer_len = dsb->buflen; dsb->buf_mixpos = DSOUND_secpos_to_bufpos(dsb, dsb->sec_mixpos, 0, NULL); }
/** * 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. */ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb) { BOOL needremix = TRUE, needresample = (dsb->freq != dsb->device->pwfx->nSamplesPerSec); DWORD bAlign = dsb->pwfx->nBlockAlign, pAlign = dsb->device->pwfx->nBlockAlign; TRACE("(%p)\n",dsb); /* calculate the 10ms write lead */ dsb->writelead = (dsb->freq / 100) * dsb->pwfx->nBlockAlign; if ((dsb->pwfx->wBitsPerSample == dsb->device->pwfx->wBitsPerSample) && (dsb->pwfx->nChannels == dsb->device->pwfx->nChannels) && !needresample) needremix = FALSE; HeapFree(GetProcessHeap(), 0, dsb->tmp_buffer); dsb->tmp_buffer = NULL; dsb->max_buffer_len = dsb->freqAcc = dsb->freqAccNext = 0; dsb->freqneeded = needresample; dsb->convert = convertbpp[dsb->pwfx->wBitsPerSample/8 - 1][dsb->device->pwfx->wBitsPerSample/8 - 1]; dsb->resampleinmixer = FALSE; if (needremix) { if (needresample) DSOUND_RecalcFreqAcc(dsb); else dsb->tmp_buffer_len = dsb->buflen / bAlign * pAlign; dsb->max_buffer_len = dsb->tmp_buffer_len; if ((dsb->max_buffer_len <= dsb->device->buflen || dsb->max_buffer_len < ds_snd_shadow_maxsize * 1024 * 1024) && ds_snd_shadow_maxsize >= 0) dsb->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, dsb->max_buffer_len); if (dsb->tmp_buffer) FillMemory(dsb->tmp_buffer, dsb->tmp_buffer_len, dsb->device->pwfx->wBitsPerSample == 8 ? 128 : 0); else dsb->resampleinmixer = TRUE; } else dsb->max_buffer_len = dsb->tmp_buffer_len = dsb->buflen; dsb->buf_mixpos = DSOUND_secpos_to_bufpos(dsb, dsb->sec_mixpos, 0, NULL); }
/** * 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; }