sound3d.c 35.1 KB
Newer Older
1 2 3 4 5
/*  			DirectSound
 *
 * Copyright 1998 Marcus Meissner
 * Copyright 1998 Rob Riggs
 * Copyright 2000-2001 TransGaming Technologies, Inc.
6
 * Copyright 2002-2003 Rok Mandeljc <rok.mandeljc@gimb.org>
7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
 */
/*
 * Most thread locking is complete. There may be a few race
 * conditions still lurking.
 *
 * Tested with a Soundblaster clone, a Gravis UltraSound Classic,
 * and a Turtle Beach Tropez+.
 *
 * TODO:
 *	Implement SetCooperativeLevel properly (need to address focus issues)
 *	Implement DirectSound3DBuffers (stubs in place)
 *	Use hardware 3D support if available
 *      Add critical section locking inside Release and AddRef methods
 *      Handle static buffers - put those in hardware, non-static not in hardware
 *      Hardware DuplicateSoundBuffer
 *      Proper volume calculation, and setting volume in HEL primary buffer
 *      Optimize WINMM and negotiate fragment size, decrease DS_HEL_MARGIN
 */

40
#include <stdarg.h>
41 42
#include <math.h>	/* Insomnia - pow() function */

43 44
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
45 46
#include "windef.h"
#include "winbase.h"
47
#include "winuser.h"
48
#include "mmsystem.h"
49
#include "winternl.h"
50 51 52 53 54 55
#include "mmddk.h"
#include "wine/debug.h"
#include "dsound.h"
#include "dsdriver.h"
#include "dsound_private.h"

56 57
/* default velocity of sound in the air */
#define DEFAULT_VELOCITY 340
58

59
WINE_DEFAULT_DEBUG_CHANNEL(dsound3d);
60

Rok Mandeljc's avatar
Rok Mandeljc committed
61 62 63 64 65
/*******************************************************************************
 *              Auxiliary functions
 */

/* scalar product (i believe it's called dot product in english) */
66
static inline D3DVALUE ScalarProduct (const D3DVECTOR *a, const D3DVECTOR *b)
Rok Mandeljc's avatar
Rok Mandeljc committed
67 68
{
	D3DVALUE c;
69
	c = (a->x*b->x) + (a->y*b->y) + (a->z*b->z);
70
	TRACE("(%f,%f,%f) * (%f,%f,%f) = %f)\n", a->x, a->y, a->z, b->x, b->y,
71
	      b->z, c);
Rok Mandeljc's avatar
Rok Mandeljc committed
72 73 74 75
	return c;
}

/* vector product (i believe it's called cross product in english */
76
static inline D3DVECTOR VectorProduct (const D3DVECTOR *a, const D3DVECTOR *b)
Rok Mandeljc's avatar
Rok Mandeljc committed
77
{
Rok Mandeljc's avatar
Rok Mandeljc committed
78
	D3DVECTOR c;
79 80 81
	c.x = (a->y*b->z) - (a->z*b->y);
	c.y = (a->z*b->x) - (a->x*b->z);
	c.z = (a->x*b->y) - (a->y*b->x);
82
	TRACE("(%f,%f,%f) x (%f,%f,%f) = (%f,%f,%f)\n", a->x, a->y, a->z, b->x, b->y,
83
	      b->z, c.x, c.y, c.z);
Rok Mandeljc's avatar
Rok Mandeljc committed
84 85 86
	return c;
}

Francois Gouget's avatar
Francois Gouget committed
87
/* magnitude (length) of vector */
88
static inline D3DVALUE VectorMagnitude (const D3DVECTOR *a)
Rok Mandeljc's avatar
Rok Mandeljc committed
89 90 91
{
	D3DVALUE l;
	l = sqrt (ScalarProduct (a, a));
92
	TRACE("|(%f,%f,%f)| = %f\n", a->x, a->y, a->z, l);
Rok Mandeljc's avatar
Rok Mandeljc committed
93 94 95 96
	return l;
}

/* conversion between radians and degrees */
Rok Mandeljc's avatar
Rok Mandeljc committed
97
static inline D3DVALUE RadToDeg (D3DVALUE angle)
Rok Mandeljc's avatar
Rok Mandeljc committed
98
{
Rok Mandeljc's avatar
Rok Mandeljc committed
99
	D3DVALUE newangle;
Rok Mandeljc's avatar
Rok Mandeljc committed
100
	newangle = angle * (360/(2*M_PI));
Rok Mandeljc's avatar
Rok Mandeljc committed
101
	TRACE("%f rad = %f deg\n", angle, newangle);
Rok Mandeljc's avatar
Rok Mandeljc committed
102 103 104
	return newangle;
}

105 106
/* angle between vectors - rad version */
static inline D3DVALUE AngleBetweenVectorsRad (const D3DVECTOR *a, const D3DVECTOR *b)
Rok Mandeljc's avatar
Rok Mandeljc committed
107
{
Rok Mandeljc's avatar
Rok Mandeljc committed
108
	D3DVALUE la, lb, product, angle, cos;
109
	/* definition of scalar product: a*b = |a|*|b|*cos... therefore: */
Rok Mandeljc's avatar
Rok Mandeljc committed
110 111 112
	product = ScalarProduct (a,b);
	la = VectorMagnitude (a);
	lb = VectorMagnitude (b);
113 114 115
	if (!la || !lb)
		return 0;

Rok Mandeljc's avatar
Rok Mandeljc committed
116
	cos = product/(la*lb);
Rok Mandeljc's avatar
Rok Mandeljc committed
117
	angle = acos(cos);
118 119
	TRACE("angle between (%f,%f,%f) and (%f,%f,%f) = %f radians (%f degrees)\n",  a->x, a->y, a->z, b->x,
	      b->y, b->z, angle, RadToDeg(angle));
Rok Mandeljc's avatar
Rok Mandeljc committed
120 121 122
	return angle;	
}

123
static inline D3DVALUE AngleBetweenVectorsDeg (const D3DVECTOR *a, const D3DVECTOR *b)
Rok Mandeljc's avatar
Rok Mandeljc committed
124
{
125
	return RadToDeg(AngleBetweenVectorsRad(a, b));
Rok Mandeljc's avatar
Rok Mandeljc committed
126 127
}

128
/* calculates vector between two points */
129
static inline D3DVECTOR VectorBetweenTwoPoints (const D3DVECTOR *a, const D3DVECTOR *b)
130 131
{
	D3DVECTOR c;
132 133 134 135 136
	c.x = b->x - a->x;
	c.y = b->y - a->y;
	c.z = b->z - a->z;
	TRACE("A (%f,%f,%f), B (%f,%f,%f), AB = (%f,%f,%f)\n", a->x, a->y, a->z, b->x, b->y,
	      b->z, c.x, c.y, c.z);
137 138 139
	return c;
}

140
/* calculates the length of vector's projection on another vector */
141
static inline D3DVALUE ProjectVector (const D3DVECTOR *a, const D3DVECTOR *p)
142 143 144 145
{
	D3DVALUE prod, result;
	prod = ScalarProduct(a, p);
	result = prod/VectorMagnitude(p);
146 147
	TRACE("length projection of (%f,%f,%f) on (%f,%f,%f) = %f\n", a->x, a->y, a->z, p->x,
              p->y, p->z, result);
148 149 150
	return result;
}

Rok Mandeljc's avatar
Rok Mandeljc committed
151 152 153
/*******************************************************************************
 *              3D Buffer and Listener mixing
 */
154

155
void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb)
Rok Mandeljc's avatar
Rok Mandeljc committed
156
{
157
	/* volume, at which the sound will be played after all calcs. */
Rok Mandeljc's avatar
Rok Mandeljc committed
158
	D3DVALUE lVolume = 0;
159
	/* stuff for distance related stuff calc. */
160
	D3DVECTOR vDistance;
Rok Mandeljc's avatar
Rok Mandeljc committed
161 162 163 164
	D3DVALUE flDistance = 0;
	/* panning related stuff */
	D3DVALUE flAngle;
	D3DVECTOR vLeft;
165
	/* doppler shift related stuff */
Alexandre Julliard's avatar
Alexandre Julliard committed
166
#if 0
167
	D3DVALUE flFreq, flBufferVel, flListenerVel;
Alexandre Julliard's avatar
Alexandre Julliard committed
168 169
#endif

170
	TRACE("(%p)\n",dsb);
171

Rok Mandeljc's avatar
Rok Mandeljc committed
172
	/* initial buffer volume */
173
	lVolume = dsb->ds3db_lVolume;
174
	
175
	switch (dsb->ds3db_ds3db.dwMode)
176
	{
177
		case DS3DMODE_DISABLE:
Rok Mandeljc's avatar
Rok Mandeljc committed
178 179
			TRACE("3D processing disabled\n");
			/* this one is here only to eliminate annoying warning message */
180
			DSOUND_RecalcVolPan (&dsb->volpan);
181
			break;
182
		case DS3DMODE_NORMAL:
183 184
			TRACE("Normal 3D processing mode\n");
			/* we need to calculate distance between buffer and listener*/
Robert Reif's avatar
Robert Reif committed
185
			vDistance = VectorBetweenTwoPoints(&dsb->ds3db_ds3db.vPosition, &dsb->device->ds3dl.vPosition);
186
			flDistance = VectorMagnitude (&vDistance);
187
			break;
188
		case DS3DMODE_HEADRELATIVE:
189 190
			TRACE("Head-relative 3D processing mode\n");
			/* distance between buffer and listener is same as buffer's position */
191
			flDistance = VectorMagnitude (&dsb->ds3db_ds3db.vPosition);
Rok Mandeljc's avatar
Rok Mandeljc committed
192 193
			break;
	}
194
	
195
	if (flDistance > dsb->ds3db_ds3db.flMaxDistance)
196 197
	{
		/* some apps don't want you to hear too distant sounds... */
198
		if (dsb->dsbd.dwFlags & DSBCAPS_MUTE3DATMAXDISTANCE)
199
		{
200 201
			dsb->volpan.lVolume = DSBVOLUME_MIN;
			DSOUND_RecalcVolPan (&dsb->volpan);		
202 203 204 205
			/* i guess mixing here would be a waste of power */
			return;
		}
		else
206
			flDistance = dsb->ds3db_ds3db.flMaxDistance;
207
	}		
208 209 210

	if (flDistance < dsb->ds3db_ds3db.flMinDistance)
		flDistance = dsb->ds3db_ds3db.flMinDistance;
211
	
212 213
	/* 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;
214
	TRACE("dist. att: Distance = %f, MinDistance = %f => adjusting volume %d to %f\n", flDistance, dsb->ds3db_ds3db.flMinDistance, dsb->ds3db_lVolume, lVolume);
Rok Mandeljc's avatar
Rok Mandeljc committed
215 216 217

	/* conning */
	/* sometimes it happens that vConeOrientation vector = (0,0,0); in this case angle is "nan" and it's useless*/
218
	if (dsb->ds3db_ds3db.vConeOrientation.x == 0 && dsb->ds3db_ds3db.vConeOrientation.y == 0 && dsb->ds3db_ds3db.vConeOrientation.z == 0)
Rok Mandeljc's avatar
Rok Mandeljc committed
219 220 221 222 223 224
	{
		TRACE("conning: cones not set\n");
	}
	else
	{
		/* calculate angle */
225
		flAngle = AngleBetweenVectorsDeg(&dsb->ds3db_ds3db.vConeOrientation, &vDistance);
Rok Mandeljc's avatar
Rok Mandeljc committed
226
		/* if by any chance it happens that OutsideConeAngle = InsideConeAngle (that means that conning has no effect) */
227
		if (dsb->ds3db_ds3db.dwInsideConeAngle != dsb->ds3db_ds3db.dwOutsideConeAngle)
Rok Mandeljc's avatar
Rok Mandeljc committed
228 229
		{
			/* my test show that for my way of calc., we need only half of angles */
230 231
			DWORD dwInsideConeAngle = dsb->ds3db_ds3db.dwInsideConeAngle/2;
			DWORD dwOutsideConeAngle = dsb->ds3db_ds3db.dwOutsideConeAngle/2;
232 233 234
			if (dwOutsideConeAngle == dwInsideConeAngle)
				++dwOutsideConeAngle;

Rok Mandeljc's avatar
Rok Mandeljc committed
235 236 237 238 239 240 241
			/* 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 */
242 243
			lVolume += ((dsb->ds3db_ds3db.lConeOutsideVolume)/((dwOutsideConeAngle) - (dwInsideConeAngle))) * flAngle;
		}
244
		TRACE("conning: Angle = %f deg; InsideConeAngle(/2) = %d deg; OutsideConeAngle(/2) = %d deg; ConeOutsideVolume = %d => adjusting volume to %f\n",
245
		       flAngle, dsb->ds3db_ds3db.dwInsideConeAngle/2, dsb->ds3db_ds3db.dwOutsideConeAngle/2, dsb->ds3db_ds3db.lConeOutsideVolume, lVolume);
Rok Mandeljc's avatar
Rok Mandeljc committed
246
	}
247
	dsb->volpan.lVolume = lVolume;
Rok Mandeljc's avatar
Rok Mandeljc committed
248 249
	
	/* panning */
Robert Reif's avatar
Robert Reif committed
250 251 252
	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) {
253 254 255 256 257
		dsb->volpan.lPan = 0;
		flAngle = 0.0;
	}
	else
	{
Robert Reif's avatar
Robert Reif committed
258 259
		vDistance = VectorBetweenTwoPoints(&dsb->device->ds3dl.vPosition, &dsb->ds3db_ds3db.vPosition);
		vLeft = VectorProduct(&dsb->device->ds3dl.vOrientFront, &dsb->device->ds3dl.vOrientTop);
260 261 262 263
		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;
	}
264
	TRACE("panning: Angle = %f rad, lPan = %d\n", flAngle, dsb->volpan.lPan);
265 266 267

	/* FIXME: Doppler Effect disabled since i have no idea which frequency to change and how to do it */
#if 0	
Rok Mandeljc's avatar
Rok Mandeljc committed
268
	/* doppler shift*/
269
	if ((VectorMagnitude(&ds3db_ds3db.vVelocity) == 0) && (VectorMagnitude(&dsb->device->ds3dl.vVelocity) == 0))
270 271 272
	{
		TRACE("doppler: Buffer and Listener don't have velocities\n");
	}
273
	else if (ds3db_ds3db.vVelocity != dsb->device->ds3dl.vVelocity)
274
	{
275
		/* calculate length of ds3db_ds3db.vVelocity component which causes Doppler Effect
276 277
		   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 */
278
		flBufferVel = ProjectVector(&dsb->ds3db_ds3db.vVelocity, &vDistance);
Francois Gouget's avatar
Francois Gouget committed
279
		/* calculate length of ds3dl.vVelocity component which causes Doppler Effect
280 281
		   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 */
Robert Reif's avatar
Robert Reif committed
282
		flListenerVel = ProjectVector(&dsb->device->ds3dl.vVelocity, &vDistance);
283
		/* formula taken from Gianicoli D.: Physics, 4th edition: */
284 285
		/* FIXME: replace dsb->freq with appropriate frequency ! */
		flFreq = dsb->freq * ((DEFAULT_VELOCITY + flListenerVel)/(DEFAULT_VELOCITY + flBufferVel));
286
		TRACE("doppler: Buffer velocity (component) = %lf, Listener velocity (component) = %lf => Doppler shift: %ld Hz -> %lf Hz\n", flBufferVel, flListenerVel,
287
		      dsb->freq, flFreq);
288
		/* FIXME: replace following line with correct frequency setting ! */
289
		dsb->freq = flFreq;
290 291
		DSOUND_RecalcFormat(dsb);
		DSOUND_MixToTemporary(dsb, 0, dsb->buflen);
292 293
	}
#endif	
Rok Mandeljc's avatar
Rok Mandeljc committed
294
	
295
	/* time for remix */
296 297 298 299 300 301 302 303
	DSOUND_RecalcVolPan(&dsb->volpan);
}

static void DSOUND_Mix3DBuffer(IDirectSoundBufferImpl *dsb)
{
	TRACE("(%p)\n",dsb);

	DSOUND_Calc3DBuffer(dsb);
Rok Mandeljc's avatar
Rok Mandeljc committed
304 305
}

306
static void DSOUND_ChangeListener(IDirectSound3DListenerImpl *ds3dl)
Rok Mandeljc's avatar
Rok Mandeljc committed
307 308
{
	int i;
309
	TRACE("(%p)\n",ds3dl);
Robert Reif's avatar
Robert Reif committed
310
	for (i = 0; i < ds3dl->device->nrofbuffers; i++)
Rok Mandeljc's avatar
Rok Mandeljc committed
311
	{
312
		/* check if this buffer is waiting for recalculation */
Robert Reif's avatar
Robert Reif committed
313
		if (ds3dl->device->buffers[i]->ds3db_need_recalc)
314
		{
Robert Reif's avatar
Robert Reif committed
315
			DSOUND_Mix3DBuffer(ds3dl->device->buffers[i]);
316
		}
Rok Mandeljc's avatar
Rok Mandeljc committed
317 318
	}
}
319 320 321 322 323 324 325 326 327

/*******************************************************************************
 *              IDirectSound3DBuffer
 */

/* IUnknown methods */
static HRESULT WINAPI IDirectSound3DBufferImpl_QueryInterface(
	LPDIRECTSOUND3DBUFFER iface, REFIID riid, LPVOID *ppobj)
{
328
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
329 330 331 332 333 334 335

	TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
	return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb, riid, ppobj);
}

static ULONG WINAPI IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface)
{
336 337
    IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
    ULONG ref = InterlockedIncrement(&(This->ref));
338
    TRACE("(%p) ref was %d\n", This, ref - 1);
339
    return ref;
340 341 342 343
}

static ULONG WINAPI IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface)
{
344 345
    IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
    ULONG ref = InterlockedDecrement(&(This->ref));
346
    TRACE("(%p) ref was %d\n", This, ref + 1);
347

348 349 350 351 352 353 354
    if (!ref) {
        This->dsb->ds3db = NULL;
        IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
        HeapFree(GetProcessHeap(), 0, This);
        TRACE("(%p) released\n", This);
    }
    return ref;
355 356 357 358 359 360 361
}

/* IDirectSound3DBuffer methods */
static HRESULT WINAPI IDirectSound3DBufferImpl_GetAllParameters(
	LPDIRECTSOUND3DBUFFER iface,
	LPDS3DBUFFER lpDs3dBuffer)
{
362
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
363 364 365
	TRACE("(%p,%p)\n",This,lpDs3dBuffer);

	if (lpDs3dBuffer == NULL) {
366
		WARN("invalid parameter: lpDs3dBuffer == NULL\n");
367 368 369 370
		return DSERR_INVALIDPARAM;
	}

	if (lpDs3dBuffer->dwSize < sizeof(*lpDs3dBuffer)) {
371
		WARN("invalid parameter: lpDs3dBuffer->dwSize = %d\n",lpDs3dBuffer->dwSize);
372 373 374
		return DSERR_INVALIDPARAM;
	}
	
375 376
	TRACE("returning: all parameters\n");
	*lpDs3dBuffer = This->dsb->ds3db_ds3db;
377 378 379 380 381 382 383 384
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeAngles(
	LPDIRECTSOUND3DBUFFER iface,
	LPDWORD lpdwInsideConeAngle,
	LPDWORD lpdwOutsideConeAngle)
{
385
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
386
	TRACE("returning: Inside Cone Angle = %d degrees; Outside Cone Angle = %d degrees\n",
387 388 389
		This->dsb->ds3db_ds3db.dwInsideConeAngle, This->dsb->ds3db_ds3db.dwOutsideConeAngle);
	*lpdwInsideConeAngle = This->dsb->ds3db_ds3db.dwInsideConeAngle;
	*lpdwOutsideConeAngle = This->dsb->ds3db_ds3db.dwOutsideConeAngle;
390 391 392 393 394 395 396
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOrientation(
	LPDIRECTSOUND3DBUFFER iface,
	LPD3DVECTOR lpvConeOrientation)
{
397
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
398
	TRACE("returning: Cone Orientation vector = (%f,%f,%f)\n",
399 400
		This->dsb->ds3db_ds3db.vConeOrientation.x,
		This->dsb->ds3db_ds3db.vConeOrientation.y,
401
		This->dsb->ds3db_ds3db.vConeOrientation.z);
402
	*lpvConeOrientation = This->dsb->ds3db_ds3db.vConeOrientation;
403 404 405 406 407 408 409
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOutsideVolume(
	LPDIRECTSOUND3DBUFFER iface,
	LPLONG lplConeOutsideVolume)
{
410
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
411
	TRACE("returning: Cone Outside Volume = %d\n", This->dsb->ds3db_ds3db.lConeOutsideVolume);
412
	*lplConeOutsideVolume = This->dsb->ds3db_ds3db.lConeOutsideVolume;
413 414 415 416 417 418 419
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DBufferImpl_GetMaxDistance(
	LPDIRECTSOUND3DBUFFER iface,
	LPD3DVALUE lpfMaxDistance)
{
420
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
421 422
	TRACE("returning: Max Distance = %f\n", This->dsb->ds3db_ds3db.flMaxDistance);
	*lpfMaxDistance = This->dsb->ds3db_ds3db.flMaxDistance;
423 424 425 426 427 428 429
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DBufferImpl_GetMinDistance(
	LPDIRECTSOUND3DBUFFER iface,
	LPD3DVALUE lpfMinDistance)
{
430
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
431 432
	TRACE("returning: Min Distance = %f\n", This->dsb->ds3db_ds3db.flMinDistance);
	*lpfMinDistance = This->dsb->ds3db_ds3db.flMinDistance;
433 434 435 436 437 438 439
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DBufferImpl_GetMode(
	LPDIRECTSOUND3DBUFFER iface,
	LPDWORD lpdwMode)
{
440
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
441
	TRACE("returning: Mode = %d\n", This->dsb->ds3db_ds3db.dwMode);
442
	*lpdwMode = This->dsb->ds3db_ds3db.dwMode;
443 444 445 446 447 448 449
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DBufferImpl_GetPosition(
	LPDIRECTSOUND3DBUFFER iface,
	LPD3DVECTOR lpvPosition)
{
450
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
451
	TRACE("returning: Position vector = (%f,%f,%f)\n",
452 453 454
		This->dsb->ds3db_ds3db.vPosition.x,
		This->dsb->ds3db_ds3db.vPosition.y,
		This->dsb->ds3db_ds3db.vPosition.z);
455
	*lpvPosition = This->dsb->ds3db_ds3db.vPosition;
456 457 458 459 460 461 462
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DBufferImpl_GetVelocity(
	LPDIRECTSOUND3DBUFFER iface,
	LPD3DVECTOR lpvVelocity)
{
463
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
464
	TRACE("returning: Velocity vector = (%f,%f,%f)\n",
465 466 467
		This->dsb->ds3db_ds3db.vVelocity.x,
		This->dsb->ds3db_ds3db.vVelocity.y,
		This->dsb->ds3db_ds3db.vVelocity.z);
468
	*lpvVelocity = This->dsb->ds3db_ds3db.vVelocity;
469 470 471 472 473 474 475 476
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DBufferImpl_SetAllParameters(
	LPDIRECTSOUND3DBUFFER iface,
	LPCDS3DBUFFER lpcDs3dBuffer,
	DWORD dwApply)
{
477
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
478
	DWORD status = DSERR_INVALIDPARAM;
479
	TRACE("(%p,%p,%x)\n",iface,lpcDs3dBuffer,dwApply);
480 481 482 483

	if (lpcDs3dBuffer == NULL) {
		WARN("invalid parameter: lpcDs3dBuffer == NULL\n");
		return status;
484
	}
485 486

	if (lpcDs3dBuffer->dwSize != sizeof(DS3DBUFFER)) {
487
		WARN("invalid parameter: lpcDs3dBuffer->dwSize = %d\n", lpcDs3dBuffer->dwSize);
488 489 490
		return status;
	}

491
	TRACE("setting: all parameters; dwApply = %d\n", dwApply);
492
	This->dsb->ds3db_ds3db = *lpcDs3dBuffer;
493

494 495 496 497 498 499
	if (dwApply == DS3D_IMMEDIATE)
	{
		DSOUND_Mix3DBuffer(This->dsb);
	}
	This->dsb->ds3db_need_recalc = TRUE;
	status = DS_OK;
500 501

	return status;
502 503 504 505 506 507 508 509
}

static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeAngles(
	LPDIRECTSOUND3DBUFFER iface,
	DWORD dwInsideConeAngle,
	DWORD dwOutsideConeAngle,
	DWORD dwApply)
{
510
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
511
	TRACE("setting: Inside Cone Angle = %d; Outside Cone Angle = %d; dwApply = %d\n",
512
		dwInsideConeAngle, dwOutsideConeAngle, dwApply);
513 514 515 516 517
	This->dsb->ds3db_ds3db.dwInsideConeAngle = dwInsideConeAngle;
	This->dsb->ds3db_ds3db.dwOutsideConeAngle = dwOutsideConeAngle;
	if (dwApply == DS3D_IMMEDIATE)
	{
		DSOUND_Mix3DBuffer(This->dsb);
518
	}
519
	This->dsb->ds3db_need_recalc = TRUE;
520 521 522 523 524 525 526 527
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOrientation(
	LPDIRECTSOUND3DBUFFER iface,
	D3DVALUE x, D3DVALUE y, D3DVALUE z,
	DWORD dwApply)
{
528
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
529
	TRACE("setting: Cone Orientation vector = (%f,%f,%f); dwApply = %d\n", x, y, z, dwApply);
530 531 532
	This->dsb->ds3db_ds3db.vConeOrientation.x = x;
	This->dsb->ds3db_ds3db.vConeOrientation.y = y;
	This->dsb->ds3db_ds3db.vConeOrientation.z = z;
533 534 535 536
	if (dwApply == DS3D_IMMEDIATE)
	{
		This->dsb->ds3db_need_recalc = FALSE;
		DSOUND_Mix3DBuffer(This->dsb);
537
	}
538
	This->dsb->ds3db_need_recalc = TRUE;
539 540 541 542 543 544 545 546
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOutsideVolume(
	LPDIRECTSOUND3DBUFFER iface,
	LONG lConeOutsideVolume,
	DWORD dwApply)
{
547
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
548
	TRACE("setting: ConeOutsideVolume = %d; dwApply = %d\n", lConeOutsideVolume, dwApply);
549 550 551 552 553
	This->dsb->ds3db_ds3db.lConeOutsideVolume = lConeOutsideVolume;
	if (dwApply == DS3D_IMMEDIATE)
	{
		This->dsb->ds3db_need_recalc = FALSE;
		DSOUND_Mix3DBuffer(This->dsb);
554
	}
555
	This->dsb->ds3db_need_recalc = TRUE;
556 557 558 559 560 561 562 563
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DBufferImpl_SetMaxDistance(
	LPDIRECTSOUND3DBUFFER iface,
	D3DVALUE fMaxDistance,
	DWORD dwApply)
{
564
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
565
	TRACE("setting: MaxDistance = %f; dwApply = %d\n", fMaxDistance, dwApply);
566 567 568 569 570
	This->dsb->ds3db_ds3db.flMaxDistance = fMaxDistance;
	if (dwApply == DS3D_IMMEDIATE)
	{
		This->dsb->ds3db_need_recalc = FALSE;
		DSOUND_Mix3DBuffer(This->dsb);
571
	}
572
	This->dsb->ds3db_need_recalc = TRUE;
573 574 575 576 577 578 579 580
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DBufferImpl_SetMinDistance(
	LPDIRECTSOUND3DBUFFER iface,
	D3DVALUE fMinDistance,
	DWORD dwApply)
{
581
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
582
	TRACE("setting: MinDistance = %f; dwApply = %d\n", fMinDistance, dwApply);
583 584 585 586 587
	This->dsb->ds3db_ds3db.flMinDistance = fMinDistance;
	if (dwApply == DS3D_IMMEDIATE)
	{
		This->dsb->ds3db_need_recalc = FALSE;
		DSOUND_Mix3DBuffer(This->dsb);
588
	}
589
	This->dsb->ds3db_need_recalc = TRUE;
590 591 592 593 594 595 596 597
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DBufferImpl_SetMode(
	LPDIRECTSOUND3DBUFFER iface,
	DWORD dwMode,
	DWORD dwApply)
{
598
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
599
	TRACE("setting: Mode = %d; dwApply = %d\n", dwMode, dwApply);
600 601 602 603 604
	This->dsb->ds3db_ds3db.dwMode = dwMode;
	if (dwApply == DS3D_IMMEDIATE)
	{
		This->dsb->ds3db_need_recalc = FALSE;
		DSOUND_Mix3DBuffer(This->dsb);
605
	}
606
	This->dsb->ds3db_need_recalc = TRUE;
607 608 609 610 611 612 613 614
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DBufferImpl_SetPosition(
	LPDIRECTSOUND3DBUFFER iface,
	D3DVALUE x, D3DVALUE y, D3DVALUE z,
	DWORD dwApply)
{
615
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
616
	TRACE("setting: Position vector = (%f,%f,%f); dwApply = %d\n", x, y, z, dwApply);
617 618 619
	This->dsb->ds3db_ds3db.vPosition.x = x;
	This->dsb->ds3db_ds3db.vPosition.y = y;
	This->dsb->ds3db_ds3db.vPosition.z = z;
620 621 622 623
	if (dwApply == DS3D_IMMEDIATE)
	{
		This->dsb->ds3db_need_recalc = FALSE;
		DSOUND_Mix3DBuffer(This->dsb);
624
	}
625
	This->dsb->ds3db_need_recalc = TRUE;
626 627 628 629 630 631 632 633
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DBufferImpl_SetVelocity(
	LPDIRECTSOUND3DBUFFER iface,
	D3DVALUE x, D3DVALUE y, D3DVALUE z,
	DWORD dwApply)
{
634
	IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
635
	TRACE("setting: Velocity vector = (%f,%f,%f); dwApply = %d\n", x, y, z, dwApply);
636 637 638
	This->dsb->ds3db_ds3db.vVelocity.x = x;
	This->dsb->ds3db_ds3db.vVelocity.y = y;
	This->dsb->ds3db_ds3db.vVelocity.z = z;
639 640 641 642
	if (dwApply == DS3D_IMMEDIATE)
	{
		This->dsb->ds3db_need_recalc = FALSE;
		DSOUND_Mix3DBuffer(This->dsb);
643
	}
644
	This->dsb->ds3db_need_recalc = TRUE;
645 646 647
	return DS_OK;
}

648
static const IDirectSound3DBufferVtbl ds3dbvt =
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
{
	/* IUnknown methods */
	IDirectSound3DBufferImpl_QueryInterface,
	IDirectSound3DBufferImpl_AddRef,
	IDirectSound3DBufferImpl_Release,
	/* IDirectSound3DBuffer methods */
	IDirectSound3DBufferImpl_GetAllParameters,
	IDirectSound3DBufferImpl_GetConeAngles,
	IDirectSound3DBufferImpl_GetConeOrientation,
	IDirectSound3DBufferImpl_GetConeOutsideVolume,
	IDirectSound3DBufferImpl_GetMaxDistance,
	IDirectSound3DBufferImpl_GetMinDistance,
	IDirectSound3DBufferImpl_GetMode,
	IDirectSound3DBufferImpl_GetPosition,
	IDirectSound3DBufferImpl_GetVelocity,
	IDirectSound3DBufferImpl_SetAllParameters,
	IDirectSound3DBufferImpl_SetConeAngles,
	IDirectSound3DBufferImpl_SetConeOrientation,
	IDirectSound3DBufferImpl_SetConeOutsideVolume,
	IDirectSound3DBufferImpl_SetMaxDistance,
	IDirectSound3DBufferImpl_SetMinDistance,
	IDirectSound3DBufferImpl_SetMode,
	IDirectSound3DBufferImpl_SetPosition,
	IDirectSound3DBufferImpl_SetVelocity,
};

675
HRESULT IDirectSound3DBufferImpl_Create(
676
	IDirectSoundBufferImpl *dsb,
677 678 679
	IDirectSound3DBufferImpl **pds3db)
{
	IDirectSound3DBufferImpl *ds3db;
680
	TRACE("(%p,%p)\n",dsb,pds3db);
681

682
	ds3db = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*ds3db));
683 684 685

	if (ds3db == NULL) {
		WARN("out of memory\n");
686
		*pds3db = 0;
687 688
		return DSERR_OUTOFMEMORY;
	}
689 690

	ds3db->ref = 0;
691
	ds3db->dsb = dsb;
692
	ds3db->lpVtbl = &ds3dbvt;
693 694

	ds3db->dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
695 696 697 698 699 700
	ds3db->dsb->ds3db_ds3db.vPosition.x = 0.0;
	ds3db->dsb->ds3db_ds3db.vPosition.y = 0.0;
	ds3db->dsb->ds3db_ds3db.vPosition.z = 0.0;
	ds3db->dsb->ds3db_ds3db.vVelocity.x = 0.0;
	ds3db->dsb->ds3db_ds3db.vVelocity.y = 0.0;
	ds3db->dsb->ds3db_ds3db.vVelocity.z = 0.0;
701 702
	ds3db->dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
	ds3db->dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
703 704 705
	ds3db->dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
	ds3db->dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
	ds3db->dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
706 707 708 709 710 711 712
	ds3db->dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
	ds3db->dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
	ds3db->dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
	ds3db->dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;

	ds3db->dsb->ds3db_need_recalc = TRUE;

713 714
	IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)dsb);

715 716 717 718
	*pds3db = ds3db;
	return S_OK;
}

719
HRESULT IDirectSound3DBufferImpl_Destroy(
720 721 722 723 724 725 726 727 728
    IDirectSound3DBufferImpl *pds3db)
{
    TRACE("(%p)\n",pds3db);

    while (IDirectSound3DBufferImpl_Release((LPDIRECTSOUND3DBUFFER)pds3db) > 0);

    return S_OK;
}

729 730 731 732 733 734 735 736
/*******************************************************************************
 *	      IDirectSound3DListener
 */

/* IUnknown methods */
static HRESULT WINAPI IDirectSound3DListenerImpl_QueryInterface(
	LPDIRECTSOUND3DLISTENER iface, REFIID riid, LPVOID *ppobj)
{
737
	IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
738 739

	TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
740

741 742 743 744 745 746 747
	if (ppobj == NULL) {
		WARN("invalid parameter\n");
		return E_INVALIDARG;
	}

	*ppobj = NULL;  /* assume failure */

748 749 750 751 752 753 754 755
	if ( IsEqualGUID(riid, &IID_IUnknown) ||
	     IsEqualGUID(riid, &IID_IDirectSound3DListener ) ) {
                IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)This);
		*ppobj = This;
		return S_OK;
	}

	if ( IsEqualGUID(riid, &IID_IDirectSoundBuffer) ) {
Robert Reif's avatar
Robert Reif committed
756 757 758 759
		if (!This->device->primary)
			PrimaryBufferImpl_Create(This->device, &(This->device->primary), &(This->device->dsbd));
		if (This->device->primary) {
			*ppobj = This->device->primary;
760 761 762
			IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)*ppobj);
			return S_OK;
		}
763 764 765 766
	}

        FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
	return E_NOINTERFACE;
767 768 769 770
}

static ULONG WINAPI IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface)
{
771 772
    IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
    ULONG ref = InterlockedIncrement(&(This->ref));
773
    TRACE("(%p) ref was %d\n", This, ref - 1);
774
    return ref;
775 776 777 778
}

static ULONG WINAPI IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface)
{
779 780
    IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
    ULONG ref = InterlockedDecrement(&(This->ref));
781
    TRACE("(%p) ref was %d\n", This, ref + 1);
782

783
    if (!ref) {
Robert Reif's avatar
Robert Reif committed
784
        This->device->listener = 0;
785 786 787 788
        HeapFree(GetProcessHeap(), 0, This);
        TRACE("(%p) released\n", This);
    }
    return ref;
789 790 791 792 793 794 795
}

/* IDirectSound3DListener methods */
static HRESULT WINAPI IDirectSound3DListenerImpl_GetAllParameter(
	LPDIRECTSOUND3DLISTENER iface,
	LPDS3DLISTENER lpDS3DL)
{
796
	IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
797 798 799
	TRACE("(%p,%p)\n",This,lpDS3DL);

	if (lpDS3DL == NULL) {
800
		WARN("invalid parameter: lpDS3DL == NULL\n");
801 802 803 804
		return DSERR_INVALIDPARAM;
	}

	if (lpDS3DL->dwSize < sizeof(*lpDS3DL)) {
805
		WARN("invalid parameter: lpDS3DL->dwSize = %d\n",lpDS3DL->dwSize);
806 807 808
		return DSERR_INVALIDPARAM;
	}
	
809
	TRACE("returning: all parameters\n");
Robert Reif's avatar
Robert Reif committed
810
	*lpDS3DL = This->device->ds3dl;
811 812 813 814 815 816 817
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DListenerImpl_GetDistanceFactor(
	LPDIRECTSOUND3DLISTENER iface,
	LPD3DVALUE lpfDistanceFactor)
{
818
	IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
Robert Reif's avatar
Robert Reif committed
819 820
	TRACE("returning: Distance Factor = %f\n", This->device->ds3dl.flDistanceFactor);
	*lpfDistanceFactor = This->device->ds3dl.flDistanceFactor;
821 822 823 824 825 826 827
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DListenerImpl_GetDopplerFactor(
	LPDIRECTSOUND3DLISTENER iface,
	LPD3DVALUE lpfDopplerFactor)
{
828
	IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
Robert Reif's avatar
Robert Reif committed
829 830
	TRACE("returning: Doppler Factor = %f\n", This->device->ds3dl.flDopplerFactor);
	*lpfDopplerFactor = This->device->ds3dl.flDopplerFactor;
831 832 833 834 835 836 837 838
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DListenerImpl_GetOrientation(
	LPDIRECTSOUND3DLISTENER iface,
	LPD3DVECTOR lpvOrientFront,
	LPD3DVECTOR lpvOrientTop)
{
839
	IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
840 841
	TRACE("returning: OrientFront vector = (%f,%f,%f); OrientTop vector = (%f,%f,%f)\n", This->device->ds3dl.vOrientFront.x,
	This->device->ds3dl.vOrientFront.y, This->device->ds3dl.vOrientFront.z, This->device->ds3dl.vOrientTop.x, This->device->ds3dl.vOrientTop.y,
Robert Reif's avatar
Robert Reif committed
842 843 844
	This->device->ds3dl.vOrientTop.z);
	*lpvOrientFront = This->device->ds3dl.vOrientFront;
	*lpvOrientTop = This->device->ds3dl.vOrientTop;
845 846 847 848 849 850 851
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DListenerImpl_GetPosition(
	LPDIRECTSOUND3DLISTENER iface,
	LPD3DVECTOR lpvPosition)
{
852
	IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
Robert Reif's avatar
Robert Reif committed
853 854
	TRACE("returning: Position vector = (%f,%f,%f)\n", This->device->ds3dl.vPosition.x, This->device->ds3dl.vPosition.y, This->device->ds3dl.vPosition.z);
	*lpvPosition = This->device->ds3dl.vPosition;
855 856 857 858 859 860 861
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DListenerImpl_GetRolloffFactor(
	LPDIRECTSOUND3DLISTENER iface,
	LPD3DVALUE lpfRolloffFactor)
{
862
	IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
Robert Reif's avatar
Robert Reif committed
863 864
	TRACE("returning: RolloffFactor = %f\n", This->device->ds3dl.flRolloffFactor);
	*lpfRolloffFactor = This->device->ds3dl.flRolloffFactor;
865 866 867 868 869 870 871
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DListenerImpl_GetVelocity(
	LPDIRECTSOUND3DLISTENER iface,
	LPD3DVECTOR lpvVelocity)
{
872
	IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
Robert Reif's avatar
Robert Reif committed
873 874
	TRACE("returning: Velocity vector = (%f,%f,%f)\n", This->device->ds3dl.vVelocity.x, This->device->ds3dl.vVelocity.y, This->device->ds3dl.vVelocity.z);
	*lpvVelocity = This->device->ds3dl.vVelocity;
875 876 877 878 879 880 881 882
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DListenerImpl_SetAllParameters(
	LPDIRECTSOUND3DLISTENER iface,
	LPCDS3DLISTENER lpcDS3DL,
	DWORD dwApply)
{
883
	IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
884
	TRACE("setting: all parameters; dwApply = %d\n", dwApply);
Robert Reif's avatar
Robert Reif committed
885
	This->device->ds3dl = *lpcDS3DL;
886 887
	if (dwApply == DS3D_IMMEDIATE)
	{
Robert Reif's avatar
Robert Reif committed
888
		This->device->ds3dl_need_recalc = FALSE;
Rok Mandeljc's avatar
Rok Mandeljc committed
889
		DSOUND_ChangeListener(This);
890
	}
Robert Reif's avatar
Robert Reif committed
891
	This->device->ds3dl_need_recalc = TRUE;
892 893 894 895 896 897 898 899
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DListenerImpl_SetDistanceFactor(
	LPDIRECTSOUND3DLISTENER iface,
	D3DVALUE fDistanceFactor,
	DWORD dwApply)
{
900
	IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
901
	TRACE("setting: Distance Factor = %f; dwApply = %d\n", fDistanceFactor, dwApply);
Robert Reif's avatar
Robert Reif committed
902
	This->device->ds3dl.flDistanceFactor = fDistanceFactor;
903 904
	if (dwApply == DS3D_IMMEDIATE)
	{
Robert Reif's avatar
Robert Reif committed
905
		This->device->ds3dl_need_recalc = FALSE;
Rok Mandeljc's avatar
Rok Mandeljc committed
906
		DSOUND_ChangeListener(This);
907
	}
Robert Reif's avatar
Robert Reif committed
908
	This->device->ds3dl_need_recalc = TRUE;
909 910 911 912 913 914 915 916
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DListenerImpl_SetDopplerFactor(
	LPDIRECTSOUND3DLISTENER iface,
	D3DVALUE fDopplerFactor,
	DWORD dwApply)
{
917
	IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
918
	TRACE("setting: Doppler Factor = %f; dwApply = %d\n", fDopplerFactor, dwApply);
Robert Reif's avatar
Robert Reif committed
919
	This->device->ds3dl.flDopplerFactor = fDopplerFactor;
920 921
	if (dwApply == DS3D_IMMEDIATE)
	{
Robert Reif's avatar
Robert Reif committed
922
		This->device->ds3dl_need_recalc = FALSE;
Rok Mandeljc's avatar
Rok Mandeljc committed
923
		DSOUND_ChangeListener(This);
924
	}
Robert Reif's avatar
Robert Reif committed
925
	This->device->ds3dl_need_recalc = TRUE;
926 927 928 929 930 931 932 933 934
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DListenerImpl_SetOrientation(
	LPDIRECTSOUND3DLISTENER iface,
	D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront,
	D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop,
	DWORD dwApply)
{
935
	IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
936
	TRACE("setting: Front vector = (%f,%f,%f); Top vector = (%f,%f,%f); dwApply = %d\n",
937
	xFront, yFront, zFront, xTop, yTop, zTop, dwApply);
Robert Reif's avatar
Robert Reif committed
938 939 940 941 942 943
	This->device->ds3dl.vOrientFront.x = xFront;
	This->device->ds3dl.vOrientFront.y = yFront;
	This->device->ds3dl.vOrientFront.z = zFront;
	This->device->ds3dl.vOrientTop.x = xTop;
	This->device->ds3dl.vOrientTop.y = yTop;
	This->device->ds3dl.vOrientTop.z = zTop;
944 945
	if (dwApply == DS3D_IMMEDIATE)
	{
Robert Reif's avatar
Robert Reif committed
946
		This->device->ds3dl_need_recalc = FALSE;
Rok Mandeljc's avatar
Rok Mandeljc committed
947
		DSOUND_ChangeListener(This);
948
	}
Robert Reif's avatar
Robert Reif committed
949
	This->device->ds3dl_need_recalc = TRUE;
950 951 952 953 954 955 956 957
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DListenerImpl_SetPosition(
	LPDIRECTSOUND3DLISTENER iface,
	D3DVALUE x, D3DVALUE y, D3DVALUE z,
	DWORD dwApply)
{
958
	IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
959
	TRACE("setting: Position vector = (%f,%f,%f); dwApply = %d\n", x, y, z, dwApply);
Robert Reif's avatar
Robert Reif committed
960 961 962
	This->device->ds3dl.vPosition.x = x;
	This->device->ds3dl.vPosition.y = y;
	This->device->ds3dl.vPosition.z = z;
963 964
	if (dwApply == DS3D_IMMEDIATE)
	{
Robert Reif's avatar
Robert Reif committed
965
		This->device->ds3dl_need_recalc = FALSE;
Rok Mandeljc's avatar
Rok Mandeljc committed
966
		DSOUND_ChangeListener(This);
967
	}
Robert Reif's avatar
Robert Reif committed
968
	This->device->ds3dl_need_recalc = TRUE;
969 970 971 972 973 974 975 976
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DListenerImpl_SetRolloffFactor(
	LPDIRECTSOUND3DLISTENER iface,
	D3DVALUE fRolloffFactor,
	DWORD dwApply)
{
977
	IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
978
	TRACE("setting: Rolloff Factor = %f; dwApply = %d\n", fRolloffFactor, dwApply);
Robert Reif's avatar
Robert Reif committed
979
	This->device->ds3dl.flRolloffFactor = fRolloffFactor;
980 981
	if (dwApply == DS3D_IMMEDIATE)
	{
Robert Reif's avatar
Robert Reif committed
982
		This->device->ds3dl_need_recalc = FALSE;
Rok Mandeljc's avatar
Rok Mandeljc committed
983
		DSOUND_ChangeListener(This);
984
	}
Robert Reif's avatar
Robert Reif committed
985
	This->device->ds3dl_need_recalc = TRUE;
986 987 988 989 990 991 992 993
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DListenerImpl_SetVelocity(
	LPDIRECTSOUND3DLISTENER iface,
	D3DVALUE x, D3DVALUE y, D3DVALUE z,
	DWORD dwApply)
{
994
	IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
995
	TRACE("setting: Velocity vector = (%f,%f,%f); dwApply = %d\n", x, y, z, dwApply);
Robert Reif's avatar
Robert Reif committed
996 997 998
	This->device->ds3dl.vVelocity.x = x;
	This->device->ds3dl.vVelocity.y = y;
	This->device->ds3dl.vVelocity.z = z;
999 1000
	if (dwApply == DS3D_IMMEDIATE)
	{
Robert Reif's avatar
Robert Reif committed
1001
		This->device->ds3dl_need_recalc = FALSE;
Rok Mandeljc's avatar
Rok Mandeljc committed
1002
		DSOUND_ChangeListener(This);
1003
	}
Robert Reif's avatar
Robert Reif committed
1004
	This->device->ds3dl_need_recalc = TRUE;
1005 1006 1007 1008 1009 1010
	return DS_OK;
}

static HRESULT WINAPI IDirectSound3DListenerImpl_CommitDeferredSettings(
	LPDIRECTSOUND3DLISTENER iface)
{
1011
	IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
Rok Mandeljc's avatar
Rok Mandeljc committed
1012 1013
	TRACE("\n");
	DSOUND_ChangeListener(This);
1014 1015 1016
	return DS_OK;
}

1017
static const IDirectSound3DListenerVtbl ds3dlvt =
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
{
	/* IUnknown methods */
	IDirectSound3DListenerImpl_QueryInterface,
	IDirectSound3DListenerImpl_AddRef,
	IDirectSound3DListenerImpl_Release,
	/* IDirectSound3DListener methods */
	IDirectSound3DListenerImpl_GetAllParameter,
	IDirectSound3DListenerImpl_GetDistanceFactor,
	IDirectSound3DListenerImpl_GetDopplerFactor,
	IDirectSound3DListenerImpl_GetOrientation,
	IDirectSound3DListenerImpl_GetPosition,
	IDirectSound3DListenerImpl_GetRolloffFactor,
	IDirectSound3DListenerImpl_GetVelocity,
	IDirectSound3DListenerImpl_SetAllParameters,
	IDirectSound3DListenerImpl_SetDistanceFactor,
	IDirectSound3DListenerImpl_SetDopplerFactor,
	IDirectSound3DListenerImpl_SetOrientation,
	IDirectSound3DListenerImpl_SetPosition,
	IDirectSound3DListenerImpl_SetRolloffFactor,
	IDirectSound3DListenerImpl_SetVelocity,
	IDirectSound3DListenerImpl_CommitDeferredSettings,
};

1041
HRESULT IDirectSound3DListenerImpl_Create(
Robert Reif's avatar
Robert Reif committed
1042 1043
	DirectSoundDevice * device,
	IDirectSound3DListenerImpl ** ppdsl)
1044
{
Robert Reif's avatar
Robert Reif committed
1045 1046
	IDirectSound3DListenerImpl *pdsl;
	TRACE("(%p,%p)\n",device,ppdsl);
1047

Robert Reif's avatar
Robert Reif committed
1048
	pdsl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*pdsl));
1049

Robert Reif's avatar
Robert Reif committed
1050
	if (pdsl == NULL) {
1051
		WARN("out of memory\n");
Robert Reif's avatar
Robert Reif committed
1052
		*ppdsl = 0;
1053 1054
		return DSERR_OUTOFMEMORY;
	}
1055

Robert Reif's avatar
Robert Reif committed
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080
	pdsl->ref = 0;
	pdsl->lpVtbl = &ds3dlvt;

	pdsl->device = device;

	pdsl->device->ds3dl.dwSize = sizeof(DS3DLISTENER);
	pdsl->device->ds3dl.vPosition.x = 0.0;
	pdsl->device->ds3dl.vPosition.y = 0.0;
	pdsl->device->ds3dl.vPosition.z = 0.0;
	pdsl->device->ds3dl.vVelocity.x = 0.0;
	pdsl->device->ds3dl.vVelocity.y = 0.0;
	pdsl->device->ds3dl.vVelocity.z = 0.0;
	pdsl->device->ds3dl.vOrientFront.x = 0.0;
	pdsl->device->ds3dl.vOrientFront.y = 0.0;
	pdsl->device->ds3dl.vOrientFront.z = 1.0;
	pdsl->device->ds3dl.vOrientTop.x = 0.0;
	pdsl->device->ds3dl.vOrientTop.y = 1.0;
	pdsl->device->ds3dl.vOrientTop.z = 0.0;
	pdsl->device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
	pdsl->device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
	pdsl->device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;

	pdsl->device->ds3dl_need_recalc = TRUE;

	*ppdsl = pdsl;
1081 1082
	return S_OK;
}