示例#1
0
文件: primary.c 项目: CepGamer/wine
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;
}
示例#2
0
文件: primary.c 项目: Sunmonds/wine
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;
}
示例#3
0
文件: sound3d.c 项目: AlexSteel/wine
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;
}
示例#4
0
文件: sound3d.c 项目: GYGit/reactos
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);
}
示例#5
0
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;
}
示例#6
0
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;
}
示例#7
0
文件: primary.c 项目: YokoZar/wine
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;
}