/** * Move freqAccNext to freqAcc, and find new values for buffer length and freqAccNext */ static void DSOUND_RecalcFreqAcc(IDirectSoundBufferImpl *dsb) { if (!dsb->freqneeded) return; dsb->freqAcc = dsb->freqAccNext; dsb->tmp_buffer_len = DSOUND_secpos_to_bufpos(dsb, dsb->buflen, 0, &dsb->freqAccNext); TRACE("New freqadjust: %04x, new buflen: %d\n", dsb->freqAccNext, dsb->tmp_buffer_len); }
/** * 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 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. */ void DSOUND_MixToTemporary(const IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD len, BOOL inmixer) { INT size; BYTE *ibp, *obp, *obp_begin; INT iAdvance = dsb->pwfx->nBlockAlign; INT oAdvance = dsb->device->pwfx->nBlockAlign; DWORD freqAcc, target_writepos = 0, overshot, maxlen; /* We resample only when needed */ if ((dsb->tmp_buffer && inmixer) || (!dsb->tmp_buffer && !inmixer) || dsb->resampleinmixer != inmixer) return; assert(writepos + len <= dsb->buflen); if (inmixer && writepos + len < dsb->buflen) len += dsb->pwfx->nBlockAlign; maxlen = DSOUND_secpos_to_bufpos(dsb, len, 0, NULL); ibp = dsb->buffer->memory + writepos; if (!inmixer) obp_begin = dsb->tmp_buffer; else if (dsb->device->tmp_buffer_len < maxlen || !dsb->device->tmp_buffer) { dsb->device->tmp_buffer_len = maxlen; if (dsb->device->tmp_buffer) dsb->device->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0, dsb->device->tmp_buffer, maxlen); else dsb->device->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, maxlen); obp_begin = dsb->device->tmp_buffer; } else obp_begin = dsb->device->tmp_buffer; TRACE("(%p, %p)\n", dsb, ibp); size = len / iAdvance; /* Check for same sample rate */ if (dsb->freq == dsb->device->pwfx->nSamplesPerSec) { TRACE("(%p) Same sample rate %d = primary %d\n", dsb, dsb->freq, dsb->device->pwfx->nSamplesPerSec); obp = obp_begin; if (!inmixer) obp += writepos/iAdvance*oAdvance; cp_fields(dsb, ibp, obp, iAdvance, oAdvance, size, 0, 1 << DSOUND_FREQSHIFT); return; } /* Mix in different sample rates */ TRACE("(%p) Adjusting frequency: %d -> %d\n", dsb, dsb->freq, dsb->device->pwfx->nSamplesPerSec); target_writepos = DSOUND_secpos_to_bufpos(dsb, writepos, dsb->sec_mixpos, &freqAcc); overshot = freqAcc >> DSOUND_FREQSHIFT; if (overshot) { if (overshot >= size) return; size -= overshot; writepos += overshot * iAdvance; if (writepos >= dsb->buflen) return; ibp = dsb->buffer->memory + writepos; freqAcc &= (1 << DSOUND_FREQSHIFT) - 1; TRACE("Overshot: %d, freqAcc: %04x\n", overshot, freqAcc); } if (!inmixer) obp = obp_begin + target_writepos; else obp = obp_begin; /* FIXME: Small problem here when we're overwriting buf_mixpos, it then STILL uses old freqAcc, not sure if it matters or not */ cp_fields(dsb, ibp, obp, iAdvance, oAdvance, size, freqAcc, dsb->freqAdjust); }