/** * 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; }
/** * 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; }
HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX passed_fmt) { HRESULT err = DSERR_BUFFERLOST; int i; WAVEFORMATEX *old_fmt; WAVEFORMATEXTENSIBLE *fmtex; BOOL forced = (device->priolevel == DSSCL_WRITEPRIMARY); TRACE("(%p,%p)\n", device, passed_fmt); if (device->priolevel == DSSCL_NORMAL) { WARN("failed priority check!\n"); return DSERR_PRIOLEVELNEEDED; } /* Let's be pedantic! */ if (passed_fmt == NULL) { WARN("invalid parameter: passed_fmt==NULL!\n"); return DSERR_INVALIDPARAM; } TRACE("(formattag=0x%04x,chans=%d,samplerate=%d," "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n", passed_fmt->wFormatTag, passed_fmt->nChannels, passed_fmt->nSamplesPerSec, passed_fmt->nAvgBytesPerSec, passed_fmt->nBlockAlign, passed_fmt->wBitsPerSample, passed_fmt->cbSize); /* **** */ RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE); EnterCriticalSection(&(device->mixlock)); old_fmt = device->pwfx; device->pwfx = DSOUND_CopyFormat(passed_fmt); fmtex = (WAVEFORMATEXTENSIBLE *)device->pwfx; if (device->pwfx == NULL) { device->pwfx = old_fmt; old_fmt = NULL; err = DSERR_OUTOFMEMORY; goto done; } DSOUND_PrimaryClose(device); err = DSOUND_ReopenDevice(device, FALSE); if(SUCCEEDED(err)) goto opened; /* requested format failed, so try others */ if(device->pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT){ device->pwfx->wFormatTag = WAVE_FORMAT_PCM; device->pwfx->wBitsPerSample = 32; device->pwfx->nAvgBytesPerSec = passed_fmt->nSamplesPerSec * device->pwfx->nBlockAlign; device->pwfx->nBlockAlign = passed_fmt->nChannels * (device->pwfx->wBitsPerSample / 8); err = DSOUND_ReopenDevice(device, FALSE); if(SUCCEEDED(err)) goto opened; } if(device->pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE && IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)){ fmtex->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; device->pwfx->wBitsPerSample = 32; device->pwfx->nAvgBytesPerSec = passed_fmt->nSamplesPerSec * device->pwfx->nBlockAlign; device->pwfx->nBlockAlign = passed_fmt->nChannels * (device->pwfx->wBitsPerSample / 8); err = DSOUND_ReopenDevice(device, FALSE); if(SUCCEEDED(err)) goto opened; } device->pwfx->wBitsPerSample = 32; device->pwfx->nAvgBytesPerSec = passed_fmt->nSamplesPerSec * device->pwfx->nBlockAlign; device->pwfx->nBlockAlign = passed_fmt->nChannels * (device->pwfx->wBitsPerSample / 8); err = DSOUND_ReopenDevice(device, FALSE); if(SUCCEEDED(err)) goto opened; device->pwfx->wBitsPerSample = 16; device->pwfx->nAvgBytesPerSec = passed_fmt->nSamplesPerSec * device->pwfx->nBlockAlign; device->pwfx->nBlockAlign = passed_fmt->nChannels * (device->pwfx->wBitsPerSample / 8); err = DSOUND_ReopenDevice(device, FALSE); if(SUCCEEDED(err)) goto opened; device->pwfx->wBitsPerSample = 8; device->pwfx->nAvgBytesPerSec = passed_fmt->nSamplesPerSec * device->pwfx->nBlockAlign; device->pwfx->nBlockAlign = passed_fmt->nChannels * (device->pwfx->wBitsPerSample / 8); err = DSOUND_ReopenDevice(device, FALSE); if(SUCCEEDED(err)) goto opened; device->pwfx->nChannels = (passed_fmt->nChannels == 2) ? 1 : 2; device->pwfx->wBitsPerSample = passed_fmt->wBitsPerSample; device->pwfx->nAvgBytesPerSec = passed_fmt->nSamplesPerSec * device->pwfx->nBlockAlign; device->pwfx->nBlockAlign = passed_fmt->nChannels * (device->pwfx->wBitsPerSample / 8); err = DSOUND_ReopenDevice(device, FALSE); if(SUCCEEDED(err)) goto opened; device->pwfx->wBitsPerSample = 32; device->pwfx->nAvgBytesPerSec = passed_fmt->nSamplesPerSec * device->pwfx->nBlockAlign; device->pwfx->nBlockAlign = passed_fmt->nChannels * (device->pwfx->wBitsPerSample / 8); err = DSOUND_ReopenDevice(device, FALSE); if(SUCCEEDED(err)) goto opened; device->pwfx->wBitsPerSample = 16; device->pwfx->nAvgBytesPerSec = passed_fmt->nSamplesPerSec * device->pwfx->nBlockAlign; device->pwfx->nBlockAlign = passed_fmt->nChannels * (device->pwfx->wBitsPerSample / 8); err = DSOUND_ReopenDevice(device, FALSE); if(SUCCEEDED(err)) goto opened; device->pwfx->wBitsPerSample = 8; device->pwfx->nAvgBytesPerSec = passed_fmt->nSamplesPerSec * device->pwfx->nBlockAlign; device->pwfx->nBlockAlign = passed_fmt->nChannels * (device->pwfx->wBitsPerSample / 8); err = DSOUND_ReopenDevice(device, FALSE); if(SUCCEEDED(err)) goto opened; WARN("No formats could be opened\n"); goto done; opened: err = DSOUND_PrimaryOpen(device); if (err != DS_OK) { WARN("DSOUND_PrimaryOpen failed\n"); goto done; } if (passed_fmt->nSamplesPerSec/100 != device->pwfx->nSamplesPerSec/100 && forced && device->buffer) { DSOUND_PrimaryClose(device); device->pwfx->nSamplesPerSec = passed_fmt->nSamplesPerSec; err = DSOUND_ReopenDevice(device, TRUE); if (FAILED(err)) WARN("DSOUND_ReopenDevice(2) failed: %08x\n", err); else if (FAILED((err = DSOUND_PrimaryOpen(device)))) WARN("DSOUND_PrimaryOpen(2) failed: %08x\n", err); } device->mix_buffer_len = DSOUND_bufpos_to_mixpos(device, device->buflen); device->mix_buffer = HeapReAlloc(GetProcessHeap(), 0, device->mix_buffer, device->mix_buffer_len); FillMemory(device->mix_buffer, device->mix_buffer_len, 0); device->mixfunction = mixfunctions[device->pwfx->wBitsPerSample/8 - 1]; device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1]; if (old_fmt->nSamplesPerSec != device->pwfx->nSamplesPerSec || old_fmt->wBitsPerSample != device->pwfx->wBitsPerSample || old_fmt->nChannels != device->pwfx->nChannels) { IDirectSoundBufferImpl** dsb = device->buffers; for (i = 0; i < device->nrofbuffers; i++, dsb++) { /* **** */ RtlAcquireResourceExclusive(&(*dsb)->lock, TRUE); (*dsb)->freqAdjust = ((DWORD64)(*dsb)->freq << DSOUND_FREQSHIFT) / device->pwfx->nSamplesPerSec; DSOUND_RecalcFormat((*dsb)); DSOUND_MixToTemporary((*dsb), 0, (*dsb)->buflen, FALSE); (*dsb)->primary_mixpos = 0; RtlReleaseResource(&(*dsb)->lock); /* **** */ } } done: LeaveCriticalSection(&(device->mixlock)); RtlReleaseResource(&(device->buffer_list_lock)); /* **** */ HeapFree(GetProcessHeap(), 0, old_fmt); return err; }
void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb) { /* volume, at which the sound will be played after all calcs. */ D3DVALUE lVolume = 0; /* stuff for distance related stuff calc. */ D3DVECTOR vDistance; D3DVALUE flDistance = 0; /* panning related stuff */ D3DVALUE flAngle; D3DVECTOR vLeft; /* doppler shift related stuff */ #if 0 D3DVALUE flFreq, flBufferVel, flListenerVel; #endif TRACE("(%p)\n",dsb); /* initial buffer volume */ lVolume = dsb->ds3db_lVolume; switch (dsb->ds3db_ds3db.dwMode) { case DS3DMODE_DISABLE: TRACE("3D processing disabled\n"); /* this one is here only to eliminate annoying warning message */ DSOUND_RecalcVolPan (&dsb->volpan); break; case DS3DMODE_NORMAL: TRACE("Normal 3D processing mode\n"); /* we need to calculate distance between buffer and listener*/ vDistance = VectorBetweenTwoPoints(&dsb->ds3db_ds3db.vPosition, &dsb->device->ds3dl.vPosition); flDistance = VectorMagnitude (&vDistance); break; case DS3DMODE_HEADRELATIVE: TRACE("Head-relative 3D processing mode\n"); /* distance between buffer and listener is same as buffer's position */ flDistance = VectorMagnitude (&dsb->ds3db_ds3db.vPosition); break; } if (flDistance > dsb->ds3db_ds3db.flMaxDistance) { /* some apps don't want you to hear too distant sounds... */ if (dsb->dsbd.dwFlags & DSBCAPS_MUTE3DATMAXDISTANCE) { dsb->volpan.lVolume = DSBVOLUME_MIN; DSOUND_RecalcVolPan (&dsb->volpan); /* i guess mixing here would be a waste of power */ return; } else flDistance = dsb->ds3db_ds3db.flMaxDistance; } if (flDistance < dsb->ds3db_ds3db.flMinDistance) flDistance = dsb->ds3db_ds3db.flMinDistance; /* attenuation proportional to the distance squared, converted to millibels as in lVolume*/ lVolume -= log10(flDistance/dsb->ds3db_ds3db.flMinDistance * flDistance/dsb->ds3db_ds3db.flMinDistance)*1000; TRACE("dist. att: Distance = %f, MinDistance = %f => adjusting volume %d to %f\n", flDistance, dsb->ds3db_ds3db.flMinDistance, dsb->ds3db_lVolume, lVolume); /* conning */ /* sometimes it happens that vConeOrientation vector = (0,0,0); in this case angle is "nan" and it's useless*/ if (dsb->ds3db_ds3db.vConeOrientation.x == 0 && dsb->ds3db_ds3db.vConeOrientation.y == 0 && dsb->ds3db_ds3db.vConeOrientation.z == 0) { TRACE("conning: cones not set\n"); } else { /* calculate angle */ flAngle = AngleBetweenVectorsDeg(&dsb->ds3db_ds3db.vConeOrientation, &vDistance); /* if by any chance it happens that OutsideConeAngle = InsideConeAngle (that means that conning has no effect) */ if (dsb->ds3db_ds3db.dwInsideConeAngle != dsb->ds3db_ds3db.dwOutsideConeAngle) { /* my test show that for my way of calc., we need only half of angles */ DWORD dwInsideConeAngle = dsb->ds3db_ds3db.dwInsideConeAngle/2; DWORD dwOutsideConeAngle = dsb->ds3db_ds3db.dwOutsideConeAngle/2; if (dwOutsideConeAngle == dwInsideConeAngle) ++dwOutsideConeAngle; /* full volume */ if (flAngle < dwInsideConeAngle) flAngle = dwInsideConeAngle; /* min (app defined) volume */ if (flAngle > dwOutsideConeAngle) flAngle = dwOutsideConeAngle; /* this probably isn't the right thing, but it's ok for the time being */ lVolume += ((dsb->ds3db_ds3db.lConeOutsideVolume)/((dwOutsideConeAngle) - (dwInsideConeAngle))) * flAngle; } TRACE("conning: Angle = %f deg; InsideConeAngle(/2) = %d deg; OutsideConeAngle(/2) = %d deg; ConeOutsideVolume = %d => adjusting volume to %f\n", flAngle, dsb->ds3db_ds3db.dwInsideConeAngle/2, dsb->ds3db_ds3db.dwOutsideConeAngle/2, dsb->ds3db_ds3db.lConeOutsideVolume, lVolume); } dsb->volpan.lVolume = lVolume; /* panning */ if (dsb->device->ds3dl.vPosition.x == dsb->ds3db_ds3db.vPosition.x && dsb->device->ds3dl.vPosition.y == dsb->ds3db_ds3db.vPosition.y && dsb->device->ds3dl.vPosition.z == dsb->ds3db_ds3db.vPosition.z) { dsb->volpan.lPan = 0; flAngle = 0.0; } else { vDistance = VectorBetweenTwoPoints(&dsb->device->ds3dl.vPosition, &dsb->ds3db_ds3db.vPosition); vLeft = VectorProduct(&dsb->device->ds3dl.vOrientFront, &dsb->device->ds3dl.vOrientTop); flAngle = AngleBetweenVectorsRad(&vLeft, &vDistance); /* for now, we'll use "linear formula" (which is probably incorrect); if someone has it in book, correct it */ dsb->volpan.lPan = 10000*2*flAngle/M_PI - 10000; } TRACE("panning: Angle = %f rad, lPan = %d\n", flAngle, dsb->volpan.lPan); /* FIXME: Doppler Effect disabled since i have no idea which frequency to change and how to do it */ #if 0 /* doppler shift*/ if ((VectorMagnitude(&ds3db_ds3db.vVelocity) == 0) && (VectorMagnitude(&dsb->device->ds3dl.vVelocity) == 0)) { TRACE("doppler: Buffer and Listener don't have velocities\n"); } else if (ds3db_ds3db.vVelocity != dsb->device->ds3dl.vVelocity) { /* calculate length of ds3db_ds3db.vVelocity component which causes Doppler Effect NOTE: if buffer moves TOWARDS the listener, it's velocity component is NEGATIVE if buffer moves AWAY from listener, it's velocity component is POSITIVE */ flBufferVel = ProjectVector(&dsb->ds3db_ds3db.vVelocity, &vDistance); /* calculate length of ds3dl.vVelocity component which causes Doppler Effect NOTE: if listener moves TOWARDS the buffer, it's velocity component is POSITIVE if listener moves AWAY from buffer, it's velocity component is NEGATIVE */ flListenerVel = ProjectVector(&dsb->device->ds3dl.vVelocity, &vDistance); /* formula taken from Gianicoli D.: Physics, 4th edition: */ /* FIXME: replace dsb->freq with appropriate frequency ! */ flFreq = dsb->freq * ((DEFAULT_VELOCITY + flListenerVel)/(DEFAULT_VELOCITY + flBufferVel)); TRACE("doppler: Buffer velocity (component) = %lf, Listener velocity (component) = %lf => Doppler shift: %ld Hz -> %lf Hz\n", flBufferVel, flListenerVel, dsb->freq, flFreq); /* FIXME: replace following line with correct frequency setting ! */ dsb->freq = flFreq; DSOUND_RecalcFormat(dsb); DSOUND_MixToTemporary(dsb, 0, dsb->buflen); } #endif /* time for remix */ DSOUND_RecalcVolPan(&dsb->volpan); }
static HRESULT DSOUND_PrimarySetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex, BOOL forced) { HRESULT err = DSERR_BUFFERLOST; int i; DWORD nSamplesPerSec, bpp, chans; LPWAVEFORMATEX oldpwfx; TRACE("(%p,%p)\n", device, wfex); if (device->priolevel == DSSCL_NORMAL) { WARN("failed priority check!\n"); return DSERR_PRIOLEVELNEEDED; } /* Let's be pedantic! */ if (wfex == NULL) { WARN("invalid parameter: wfex==NULL!\n"); return DSERR_INVALIDPARAM; } TRACE("(formattag=0x%04x,chans=%d,samplerate=%d," "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n", wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec, wfex->nAvgBytesPerSec, wfex->nBlockAlign, wfex->wBitsPerSample, wfex->cbSize); /* **** */ RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE); EnterCriticalSection(&(device->mixlock)); nSamplesPerSec = device->pwfx->nSamplesPerSec; bpp = device->pwfx->wBitsPerSample; chans = device->pwfx->nChannels; oldpwfx = device->pwfx; device->pwfx = DSOUND_CopyFormat(wfex); if (device->pwfx == NULL) { device->pwfx = oldpwfx; oldpwfx = NULL; err = DSERR_OUTOFMEMORY; goto done; } if (!(device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMSETFORMAT) && device->hwbuf) { err = IDsDriverBuffer_SetFormat(device->hwbuf, device->pwfx); /* On bad format, try to re-create, big chance it will work then, only do this if we <HAVE> to */ if (forced && (device->pwfx->nSamplesPerSec/100 != wfex->nSamplesPerSec/100 || err == DSERR_BADFORMAT)) { DWORD cp_size = wfex->wFormatTag == WAVE_FORMAT_PCM ? sizeof(PCMWAVEFORMAT) : sizeof(WAVEFORMATEX) + wfex->cbSize; err = DSERR_BUFFERLOST; CopyMemory(device->pwfx, wfex, cp_size); } if (err != DSERR_BUFFERLOST && FAILED(err)) { DWORD size = DSOUND_GetFormatSize(oldpwfx); WARN("IDsDriverBuffer_SetFormat failed\n"); if (!forced) { CopyMemory(device->pwfx, oldpwfx, size); err = DS_OK; } goto done; } if (err == S_FALSE) { /* ALSA specific: S_FALSE tells that recreation was successful, * but size and location may be changed, and buffer has to be restarted * I put it here, so if frequency doesn't match the error will be changed to DSERR_BUFFERLOST * and the entire re-initialization will occur anyway */ IDsDriverBuffer_Lock(device->hwbuf, (LPVOID *)&device->buffer, &device->buflen, NULL, NULL, 0, 0, DSBLOCK_ENTIREBUFFER); IDsDriverBuffer_Unlock(device->hwbuf, device->buffer, 0, NULL, 0); if (device->state == STATE_PLAYING) device->state = STATE_STARTING; else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED; device->pwplay = device->pwqueue = device->playpos = device->mixpos = 0; err = DS_OK; } DSOUND_RecalcPrimary(device); } if (err == DSERR_BUFFERLOST) { DSOUND_PrimaryClose(device); err = DSOUND_ReopenDevice(device, FALSE); if (FAILED(err)) { WARN("DSOUND_ReopenDevice failed: %08x\n", err); goto done; } err = DSOUND_PrimaryOpen(device); if (err != DS_OK) { WARN("DSOUND_PrimaryOpen failed\n"); goto done; } if (wfex->nSamplesPerSec/100 != device->pwfx->nSamplesPerSec/100 && forced && device->buffer) { DSOUND_PrimaryClose(device); device->pwfx->nSamplesPerSec = wfex->nSamplesPerSec; err = DSOUND_ReopenDevice(device, TRUE); if (FAILED(err)) WARN("DSOUND_ReopenDevice(2) failed: %08x\n", err); else if (FAILED((err = DSOUND_PrimaryOpen(device)))) WARN("DSOUND_PrimaryOpen(2) failed: %08x\n", err); } } device->mix_buffer_len = DSOUND_bufpos_to_mixpos(device, device->buflen); device->mix_buffer = HeapReAlloc(GetProcessHeap(), 0, device->mix_buffer, device->mix_buffer_len); FillMemory(device->mix_buffer, device->mix_buffer_len, 0); device->mixfunction = mixfunctions[device->pwfx->wBitsPerSample/8 - 1]; device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1]; if (nSamplesPerSec != device->pwfx->nSamplesPerSec || bpp != device->pwfx->wBitsPerSample || chans != device->pwfx->nChannels) { IDirectSoundBufferImpl** dsb = device->buffers; for (i = 0; i < device->nrofbuffers; i++, dsb++) { /* **** */ RtlAcquireResourceExclusive(&(*dsb)->lock, TRUE); (*dsb)->freqAdjust = ((DWORD64)(*dsb)->freq << DSOUND_FREQSHIFT) / device->pwfx->nSamplesPerSec; DSOUND_RecalcFormat((*dsb)); DSOUND_MixToTemporary((*dsb), 0, (*dsb)->buflen, FALSE); (*dsb)->primary_mixpos = 0; RtlReleaseResource(&(*dsb)->lock); /* **** */ } } done: LeaveCriticalSection(&(device->mixlock)); RtlReleaseResource(&(device->buffer_list_lock)); /* **** */ HeapFree(GetProcessHeap(), 0, oldpwfx); return err; }
/** * 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; }
HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex) { HRESULT err = DSERR_BUFFERLOST; int i; DWORD nSamplesPerSec, bpp, chans; LPWAVEFORMATEX oldpwfx; BOOL forced = device->priolevel == DSSCL_WRITEPRIMARY; TRACE("(%p,%p)\n", device, wfex); if (device->priolevel == DSSCL_NORMAL) { WARN("failed priority check!\n"); return DSERR_PRIOLEVELNEEDED; } /* Let's be pedantic! */ if (wfex == NULL) { WARN("invalid parameter: wfex==NULL!\n"); return DSERR_INVALIDPARAM; } TRACE("(formattag=0x%04x,chans=%d,samplerate=%d," "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n", wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec, wfex->nAvgBytesPerSec, wfex->nBlockAlign, wfex->wBitsPerSample, wfex->cbSize); /* **** */ RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE); EnterCriticalSection(&(device->mixlock)); nSamplesPerSec = device->pwfx->nSamplesPerSec; bpp = device->pwfx->wBitsPerSample; chans = device->pwfx->nChannels; oldpwfx = device->pwfx; device->pwfx = DSOUND_CopyFormat(wfex); if (device->pwfx == NULL) { device->pwfx = oldpwfx; oldpwfx = NULL; err = DSERR_OUTOFMEMORY; goto done; } DSOUND_PrimaryClose(device); err = DSOUND_ReopenDevice(device, FALSE); if (FAILED(err)) { WARN("DSOUND_ReopenDevice failed: %08x\n", err); goto done; } err = DSOUND_PrimaryOpen(device); if (err != DS_OK) { WARN("DSOUND_PrimaryOpen failed\n"); goto done; } if (wfex->nSamplesPerSec/100 != device->pwfx->nSamplesPerSec/100 && forced && device->buffer) { DSOUND_PrimaryClose(device); device->pwfx->nSamplesPerSec = wfex->nSamplesPerSec; err = DSOUND_ReopenDevice(device, TRUE); if (FAILED(err)) WARN("DSOUND_ReopenDevice(2) failed: %08x\n", err); else if (FAILED((err = DSOUND_PrimaryOpen(device)))) WARN("DSOUND_PrimaryOpen(2) failed: %08x\n", err); } device->mix_buffer_len = DSOUND_bufpos_to_mixpos(device, device->buflen); device->mix_buffer = HeapReAlloc(GetProcessHeap(), 0, device->mix_buffer, device->mix_buffer_len); FillMemory(device->mix_buffer, device->mix_buffer_len, 0); device->mixfunction = mixfunctions[device->pwfx->wBitsPerSample/8 - 1]; device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1]; if (nSamplesPerSec != device->pwfx->nSamplesPerSec || bpp != device->pwfx->wBitsPerSample || chans != device->pwfx->nChannels) { IDirectSoundBufferImpl** dsb = device->buffers; for (i = 0; i < device->nrofbuffers; i++, dsb++) { /* **** */ RtlAcquireResourceExclusive(&(*dsb)->lock, TRUE); (*dsb)->freqAdjust = ((DWORD64)(*dsb)->freq << DSOUND_FREQSHIFT) / device->pwfx->nSamplesPerSec; DSOUND_RecalcFormat((*dsb)); DSOUND_MixToTemporary((*dsb), 0, (*dsb)->buflen, FALSE); (*dsb)->primary_mixpos = 0; RtlReleaseResource(&(*dsb)->lock); /* **** */ } } done: LeaveCriticalSection(&(device->mixlock)); RtlReleaseResource(&(device->buffer_list_lock)); /* **** */ HeapFree(GetProcessHeap(), 0, oldpwfx); return err; }