static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device, WAVEFORMATEX *wfx, DWORD frames, BOOL forcewave) { IDirectSoundBufferImpl** dsb = device->buffers; LPBYTE newbuf; DWORD new_buflen; BOOL mixfloat = FALSE; int i; TRACE("(%p)\n", device); new_buflen = device->buflen; new_buflen -= new_buflen % wfx->nBlockAlign; if (wfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT || (wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE && IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)wfx)->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))) mixfloat = TRUE; /* reallocate emulated primary buffer */ if (forcewave) { if (device->buffer) newbuf = HeapReAlloc(GetProcessHeap(), 0, device->buffer, new_buflen); else newbuf = HeapAlloc(GetProcessHeap(), 0, new_buflen); if (!newbuf) { ERR("failed to allocate primary buffer\n"); return DSERR_OUTOFMEMORY; } FillMemory(newbuf, new_buflen, (wfx->wBitsPerSample == 8) ? 128 : 0); } else if (!mixfloat) { DWORD alloc_len = frames * sizeof(float); if (device->buffer) newbuf = HeapReAlloc(GetProcessHeap(), 0, device->buffer, alloc_len); else newbuf = HeapAlloc(GetProcessHeap(), 0, alloc_len); if (!newbuf) { ERR("failed to allocate primary buffer\n"); return DSERR_OUTOFMEMORY; } FillMemory(newbuf, alloc_len, (wfx->wBitsPerSample == 8) ? 128 : 0); } else { HeapFree(GetProcessHeap(), 0, device->buffer); newbuf = NULL; } device->buffer = newbuf; device->buflen = new_buflen; HeapFree(GetProcessHeap(), 0, device->pwfx); device->pwfx = wfx; device->writelead = (wfx->nSamplesPerSec / 100) * wfx->nBlockAlign; TRACE("buflen: %u, fraglen: %u\n", device->buflen, device->fraglen); if (!mixfloat) device->normfunction = normfunctions[wfx->wBitsPerSample/8 - 1]; else device->normfunction = NULL; device->playpos = 0; for (i = 0; i < device->nrofbuffers; i++) { RtlAcquireResourceExclusive(&dsb[i]->lock, TRUE); DSOUND_RecalcFormat(dsb[i]); RtlReleaseResource(&dsb[i]->lock); } return DS_OK; }
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, flAngle2; D3DVECTOR vLeft; int i, num_main_speakers; float a, ingain; /* doppler shift related stuff */ 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); return; case DS3DMODE_NORMAL: TRACE("Normal 3D processing mode\n"); /* we need to calculate distance between buffer and listener*/ vDistance = VectorBetweenTwoPoints(&dsb->device->ds3dl.vPosition, &dsb->ds3db_ds3db.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 */ vDistance = dsb->ds3db_ds3db.vPosition; flDistance = VectorMagnitude (&vDistance); 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 * dsb->device->ds3dl.flRolloffFactor; 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 { D3DVECTOR vDistanceInv; vDistanceInv.x = -vDistance.x; vDistanceInv.y = -vDistance.y; vDistanceInv.z = -vDistance.z; /* calculate angle */ flAngle = AngleBetweenVectorsDeg(&dsb->ds3db_ds3db.vConeOrientation, &vDistanceInv); /* 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 += ((flAngle - dwInsideConeAngle)/(dwOutsideConeAngle - dwInsideConeAngle)) * dsb->ds3db_ds3db.lConeOutsideVolume; } 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; ingain = pow(2.0, dsb->volpan.lVolume / 600.0) * 0xffff; if (dsb->device->pwfx->nChannels == 1) { dsb->volpan.dwTotalAmpFactor[0] = ingain; return; } /* panning */ if (vDistance.x == 0.0f && vDistance.y == 0.0f && vDistance.z == 0.0f) flAngle = 0.0; else { vLeft = VectorProduct(&dsb->device->ds3dl.vOrientFront, &dsb->device->ds3dl.vOrientTop); /* To calculate angle to sound source we need to: * 1) Get angle between vDistance and a plane on which angle to sound source should be 0. * Such a plane is given by vectors vOrientFront and vOrientTop, and angle between vector * and a plane equals to M_PI_2 - angle between vector and normal to this plane (vLeft in this case). * 2) Determine if the source is behind or in front of us by calculating angle between vDistance * and vOrientFront. */ flAngle = AngleBetweenVectorsRad(&vLeft, &vDistance); flAngle2 = AngleBetweenVectorsRad(&dsb->device->ds3dl.vOrientFront, &vDistance); if (flAngle2 > M_PI_2) flAngle = -flAngle; flAngle -= M_PI_2; if (flAngle < -M_PI) flAngle += 2*M_PI; } 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) { D3DVALUE flFreq, flBufferVel, flListenerVel; /* doppler shift*/ if (!VectorMagnitude(&dsb->ds3db_ds3db.vVelocity) && !VectorMagnitude(&dsb->device->ds3dl.vVelocity)) { TRACE("doppler: Buffer and Listener don't have velocities\n"); } else if (!(dsb->ds3db_ds3db.vVelocity.x == dsb->device->ds3dl.vVelocity.x && dsb->ds3db_ds3db.vVelocity.y == dsb->device->ds3dl.vVelocity.y && dsb->ds3db_ds3db.vVelocity.z == dsb->device->ds3dl.vVelocity.z)) { /* 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) = %f, Listener velocity (component) = %f => Doppler shift: %d Hz -> %f Hz\n", flBufferVel, flListenerVel, dsb->freq, flFreq); /* FIXME: replace following line with correct frequency setting ! */ dsb->freq = flFreq; DSOUND_RecalcFormat(dsb); } } for (i = 0; i < dsb->device->pwfx->nChannels; i++) dsb->volpan.dwTotalAmpFactor[i] = 0; num_main_speakers = dsb->device->pwfx->nChannels; if (dsb->device->lfe_channel != -1) { dsb->volpan.dwTotalAmpFactor[dsb->device->lfe_channel] = ingain; num_main_speakers--; } /* adapted from OpenAL's Alc/panning.c */ for (i = 0; i < num_main_speakers - 1; i++) { if(flAngle >= dsb->device->speaker_angles[i] && flAngle < dsb->device->speaker_angles[i+1]) { /* Sound is between speakers i and i+1 */ a = (flAngle-dsb->device->speaker_angles[i]) / (dsb->device->speaker_angles[i+1]-dsb->device->speaker_angles[i]); dsb->volpan.dwTotalAmpFactor[dsb->device->speaker_num[i]] = sqrtf(1.0f-a) * ingain; dsb->volpan.dwTotalAmpFactor[dsb->device->speaker_num[i+1]] = sqrtf(a) * ingain; return; } } /* Sound is between last and first speakers */ if (flAngle < dsb->device->speaker_angles[0]) { flAngle += M_PI*2.0f; } a = (flAngle-dsb->device->speaker_angles[i]) / (M_PI*2.0f + dsb->device->speaker_angles[0]-dsb->device->speaker_angles[i]); dsb->volpan.dwTotalAmpFactor[dsb->device->speaker_num[i]] = sqrtf(1.0f-a) * ingain; dsb->volpan.dwTotalAmpFactor[dsb->device->speaker_num[0]] = sqrtf(a) * ingain; }
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); }
HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device) { IDirectSoundBufferImpl** dsb = device->buffers; LPBYTE newbuf; int i; TRACE("(%p)\n", device); device->fraglen = DSOUND_fraglen(device); /* on original windows, the buffer it set to a fixed size, no matter what the settings are. on windows this size is always fixed (tested on win-xp) */ if (!device->buflen) device->buflen = ds_hel_buflen; device->buflen -= device->buflen % device->pwfx->nBlockAlign; while(device->buflen < device->fraglen * device->prebuf){ device->buflen += ds_hel_buflen; device->buflen -= device->buflen % device->pwfx->nBlockAlign; } HeapFree(GetProcessHeap(), 0, device->mix_buffer); device->mix_buffer_len = (device->buflen / (device->pwfx->wBitsPerSample / 8)) * sizeof(float); device->mix_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, device->mix_buffer_len); if (!device->mix_buffer) return DSERR_OUTOFMEMORY; if (device->state == STATE_PLAYING) device->state = STATE_STARTING; else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED; /* reallocate emulated primary buffer */ if (device->buffer) newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer, device->buflen); else newbuf = HeapAlloc(GetProcessHeap(),0, device->buflen); if (!newbuf) { ERR("failed to allocate primary buffer\n"); return DSERR_OUTOFMEMORY; /* but the old buffer might still exist and must be re-prepared */ } device->writelead = (device->pwfx->nSamplesPerSec / 100) * device->pwfx->nBlockAlign; device->buffer = newbuf; TRACE("buflen: %u, fraglen: %u, mix_buffer_len: %u\n", device->buflen, device->fraglen, device->mix_buffer_len); if(device->pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT || (device->pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE && IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)device->pwfx)->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))) device->normfunction = normfunctions[4]; else device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1]; FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0); FillMemory(device->mix_buffer, device->mix_buffer_len, 0); device->playpos = 0; if (device->pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT || (device->pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE && IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)device->pwfx)->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))) device->normfunction = normfunctions[4]; else device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1]; for (i = 0; i < device->nrofbuffers; i++) { RtlAcquireResourceExclusive(&dsb[i]->lock, TRUE); DSOUND_RecalcFormat(dsb[i]); RtlReleaseResource(&dsb[i]->lock); } return DS_OK; }
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; }
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; }