mcicda: Exclude unused headers.
[wine] / dlls / dsound / sound3d.c
1 /*                      DirectSound
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998 Rob Riggs
5  * Copyright 2000-2001 TransGaming Technologies, Inc.
6  * Copyright 2002-2003 Rok Mandeljc <rok.mandeljc@gimb.org>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * 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  * Most thread locking is complete. There may be a few race
24  * conditions still lurking.
25  *
26  * Tested with a Soundblaster clone, a Gravis UltraSound Classic,
27  * and a Turtle Beach Tropez+.
28  *
29  * TODO:
30  *      Implement SetCooperativeLevel properly (need to address focus issues)
31  *      Implement DirectSound3DBuffers (stubs in place)
32  *      Use hardware 3D support if available
33  *      Add critical section locking inside Release and AddRef methods
34  *      Handle static buffers - put those in hardware, non-static not in hardware
35  *      Hardware DuplicateSoundBuffer
36  *      Proper volume calculation, and setting volume in HEL primary buffer
37  *      Optimize WINMM and negotiate fragment size, decrease DS_HEL_MARGIN
38  */
39
40 #include <stdarg.h>
41 #include <math.h>       /* Insomnia - pow() function */
42
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "windef.h"
46 #include "winbase.h"
47 #include "winuser.h"
48 #include "mmsystem.h"
49 #include "winternl.h"
50 #include "mmddk.h"
51 #include "wine/debug.h"
52 #include "dsound.h"
53 #include "dsdriver.h"
54 #include "dsound_private.h"
55
56 /* default intensity level for human ears */
57 #define DEFAULT_INTENSITY 0.000000000001f
58 /* default velocity of sound in the air */
59 #define DEFAULT_VELOCITY 340
60
61 WINE_DEFAULT_DEBUG_CHANNEL(dsound3d);
62
63 /*******************************************************************************
64  *              Auxiliary functions
65  */
66
67 /* scalar product (i believe it's called dot product in english) */
68 static inline D3DVALUE ScalarProduct (const D3DVECTOR *a, const D3DVECTOR *b)
69 {
70         D3DVALUE c;
71         c = (a->x*b->x) + (a->y*b->y) + (a->z*b->z);
72         TRACE("(%f,%f,%f) * (%f,%f,%f) = %f)\n", a->x, a->y, a->z, b->x, b->y,
73               b->z, c);
74         return c;
75 }
76
77 /* vector product (i believe it's called cross product in english */
78 static inline D3DVECTOR VectorProduct (const D3DVECTOR *a, const D3DVECTOR *b)
79 {
80         D3DVECTOR c;
81         c.x = (a->y*b->z) - (a->z*b->y);
82         c.y = (a->z*b->x) - (a->x*b->z);
83         c.z = (a->x*b->y) - (a->y*b->x);
84         TRACE("(%f,%f,%f) x (%f,%f,%f) = (%f,%f,%f)\n", a->x, a->y, a->z, b->x, b->y,
85               b->z, c.x, c.y, c.z);
86         return c;
87 }
88
89 /* magnitude (length) of vector */
90 static inline D3DVALUE VectorMagnitude (const D3DVECTOR *a)
91 {
92         D3DVALUE l;
93         l = sqrt (ScalarProduct (a, a));
94         TRACE("|(%f,%f,%f)| = %f\n", a->x, a->y, a->z, l);
95         return l;
96 }
97
98 /* conversion between radians and degrees */
99 static inline D3DVALUE RadToDeg (D3DVALUE angle)
100 {
101         D3DVALUE newangle;
102         newangle = angle * (360/(2*M_PI));
103         TRACE("%f rad = %f deg\n", angle, newangle);
104         return newangle;
105 }
106
107 /* angle between vectors - deg version */
108 static inline D3DVALUE AngleBetweenVectorsDeg (const D3DVECTOR *a, const D3DVECTOR *b)
109 {
110         D3DVALUE la, lb, product, angle, cos;
111         /* definition of scalar product: a*b = |a|*|b|*cos...therefore: */
112         product = ScalarProduct (a,b);
113         la = VectorMagnitude (a);
114         lb = VectorMagnitude (b);
115         cos = product/(la*lb);
116         angle = acos(cos);
117         /* we now have angle in radians */
118         angle = RadToDeg(angle);
119         TRACE("angle between (%f,%f,%f) and (%f,%f,%f) = %f degrees\n",  a->x, a->y, a->z, b->x,
120               b->y, b->z, angle);
121         return angle;   
122 }
123
124 /* angle between vectors - rad version */
125 static inline D3DVALUE AngleBetweenVectorsRad (const D3DVECTOR *a, const D3DVECTOR *b)
126 {
127         D3DVALUE la, lb, product, angle, cos;
128         /* definition of scalar product: a*b = |a|*|b|*cos...therefore: */
129         product = ScalarProduct (a,b);
130         la = VectorMagnitude (a);
131         lb = VectorMagnitude (b);
132         cos = product/(la*lb);
133         angle = acos(cos);
134         TRACE("angle between (%f,%f,%f) and (%f,%f,%f) = %f radians\n",  a->x, a->y, a->z, b->x,
135               b->y, b->z, angle);
136         return angle;   
137 }
138
139 /* calculates vector between two points */
140 static inline D3DVECTOR VectorBetweenTwoPoints (const D3DVECTOR *a, const D3DVECTOR *b)
141 {
142         D3DVECTOR c;
143         c.x = b->x - a->x;
144         c.y = b->y - a->y;
145         c.z = b->z - a->z;
146         TRACE("A (%f,%f,%f), B (%f,%f,%f), AB = (%f,%f,%f)\n", a->x, a->y, a->z, b->x, b->y,
147               b->z, c.x, c.y, c.z);
148         return c;
149 }
150
151 /* calculates the length of vector's projection on another vector */
152 static inline D3DVALUE ProjectVector (const D3DVECTOR *a, const D3DVECTOR *p)
153 {
154         D3DVALUE prod, result;
155         prod = ScalarProduct(a, p);
156         result = prod/VectorMagnitude(p);
157         TRACE("length projection of (%f,%f,%f) on (%f,%f,%f) = %f\n", a->x, a->y, a->z, p->x,
158               p->y, p->z, result);
159         return result;
160 }
161
162 /*******************************************************************************
163  *              3D Buffer and Listener mixing
164  */
165
166 void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb)
167 {
168         /* volume, at which the sound will be played after all calcs. */
169         D3DVALUE lVolume = 0;
170         /* intensity (used for distance related stuff) */
171         double flIntensity;
172         double flTemp;
173         /* stuff for distance related stuff calc. */
174         D3DVECTOR vDistance;
175         D3DVALUE flDistance = 0;
176         /* panning related stuff */
177         D3DVALUE flAngle;
178         D3DVECTOR vLeft;
179         /* doppler shift related stuff */
180 #if 0
181         D3DVALUE flFreq, flBufferVel, flListenerVel;
182 #endif
183
184         TRACE("(%p)\n",dsb);
185
186         /* initial buffer volume */
187         lVolume = dsb->ds3db_lVolume;
188         
189         switch (dsb->ds3db_ds3db.dwMode)
190         {
191                 case DS3DMODE_DISABLE:
192                         TRACE("3D processing disabled\n");
193                         /* this one is here only to eliminate annoying warning message */
194                         DSOUND_RecalcVolPan (&dsb->volpan);
195                         DSOUND_ForceRemix (dsb);
196                         break;
197                 case DS3DMODE_NORMAL:
198                         TRACE("Normal 3D processing mode\n");
199                         /* we need to calculate distance between buffer and listener*/
200                         vDistance = VectorBetweenTwoPoints(&dsb->ds3db_ds3db.vPosition, &dsb->device->ds3dl.vPosition);
201                         flDistance = VectorMagnitude (&vDistance);
202                         break;
203                 case DS3DMODE_HEADRELATIVE:
204                         TRACE("Head-relative 3D processing mode\n");
205                         /* distance between buffer and listener is same as buffer's position */
206                         flDistance = VectorMagnitude (&dsb->ds3db_ds3db.vPosition);
207                         break;
208         }
209         
210         if (flDistance > dsb->ds3db_ds3db.flMaxDistance)
211         {
212                 /* some apps don't want you to hear too distant sounds... */
213                 if (dsb->dsbd.dwFlags & DSBCAPS_MUTE3DATMAXDISTANCE)
214                 {
215                         dsb->volpan.lVolume = DSBVOLUME_MIN;
216                         DSOUND_RecalcVolPan (&dsb->volpan);             
217                         /* i guess mixing here would be a waste of power */
218                         return;
219                 }
220                 else
221                         flDistance = dsb->ds3db_ds3db.flMaxDistance;
222         }               
223
224         if (flDistance < dsb->ds3db_ds3db.flMinDistance)
225                 flDistance = dsb->ds3db_ds3db.flMinDistance;
226         
227         /* the following formula is taken from my physics book. I think it's ok for the *real* world...i hope m$ does it that way */
228         lVolume += 10000; /* ms likes working with negative volume...i don't */
229         lVolume /= 1000; /* convert hundreths of dB into B */
230         /* intensity level (loudness) = log10(Intensity/DefaultIntensity)...therefore */
231         flIntensity = pow(10,lVolume)*DEFAULT_INTENSITY;        
232         flTemp = (flDistance/dsb->ds3db_ds3db.flMinDistance)*(flDistance/dsb->ds3db_ds3db.flMinDistance);
233         flIntensity /= flTemp;
234         lVolume = log10(flIntensity/DEFAULT_INTENSITY);
235         lVolume *= 1000; /* convert back to hundreths of dB */
236         lVolume -= 10000; /* we need to do it in ms way */
237         TRACE("dist. att: Distance = %f, MinDistance = %f => adjusting volume %d to %f\n", flDistance, dsb->ds3db_ds3db.flMinDistance, dsb->ds3db_lVolume, lVolume);
238
239         /* conning */
240         /* sometimes it happens that vConeOrientation vector = (0,0,0); in this case angle is "nan" and it's useless*/
241         if (dsb->ds3db_ds3db.vConeOrientation.x == 0 && dsb->ds3db_ds3db.vConeOrientation.y == 0 && dsb->ds3db_ds3db.vConeOrientation.z == 0)
242         {
243                 TRACE("conning: cones not set\n");
244         }
245         else
246         {
247                 /* calculate angle */
248                 flAngle = AngleBetweenVectorsDeg(&dsb->ds3db_ds3db.vConeOrientation, &vDistance);
249                 /* if by any chance it happens that OutsideConeAngle = InsideConeAngle (that means that conning has no effect) */
250                 if (dsb->ds3db_ds3db.dwInsideConeAngle != dsb->ds3db_ds3db.dwOutsideConeAngle)
251                 {
252                         /* my test show that for my way of calc., we need only half of angles */
253                         DWORD dwInsideConeAngle = dsb->ds3db_ds3db.dwInsideConeAngle/2;
254                         DWORD dwOutsideConeAngle = dsb->ds3db_ds3db.dwOutsideConeAngle/2;
255                         /* full volume */
256                         if (flAngle < dwInsideConeAngle)
257                                 flAngle = dwInsideConeAngle;
258                         /* min (app defined) volume */
259                         if (flAngle > dwOutsideConeAngle)
260                                 flAngle = dwOutsideConeAngle;
261                         /* this probably isn't the right thing, but it's ok for the time being */
262                         lVolume += ((dsb->ds3db_ds3db.lConeOutsideVolume)/((dwOutsideConeAngle) - (dwInsideConeAngle))) * flAngle;
263                 }
264                 TRACE("conning: Angle = %f deg; InsideConeAngle(/2) = %d deg; OutsideConeAngle(/2) = %d deg; ConeOutsideVolume = %d => adjusting volume to %f\n",
265                        flAngle, dsb->ds3db_ds3db.dwInsideConeAngle/2, dsb->ds3db_ds3db.dwOutsideConeAngle/2, dsb->ds3db_ds3db.lConeOutsideVolume, lVolume);
266         }
267         dsb->volpan.lVolume = lVolume;
268         
269         /* panning */
270         if (dsb->device->ds3dl.vPosition.x == dsb->ds3db_ds3db.vPosition.x &&
271             dsb->device->ds3dl.vPosition.y == dsb->ds3db_ds3db.vPosition.y &&
272             dsb->device->ds3dl.vPosition.z == dsb->ds3db_ds3db.vPosition.z) {
273                 dsb->volpan.lPan = 0;
274                 flAngle = 0.0;
275         }
276         else
277         {
278                 vDistance = VectorBetweenTwoPoints(&dsb->device->ds3dl.vPosition, &dsb->ds3db_ds3db.vPosition);
279                 vLeft = VectorProduct(&dsb->device->ds3dl.vOrientFront, &dsb->device->ds3dl.vOrientTop);
280                 flAngle = AngleBetweenVectorsRad(&vLeft, &vDistance);
281                 /* for now, we'll use "linear formula" (which is probably incorrect); if someone has it in book, correct it */
282                 dsb->volpan.lPan = 10000*2*flAngle/M_PI - 10000;
283         }
284         TRACE("panning: Angle = %f rad, lPan = %d\n", flAngle, dsb->volpan.lPan);
285
286         /* FIXME: Doppler Effect disabled since i have no idea which frequency to change and how to do it */
287 #if 0   
288         /* doppler shift*/
289         if ((VectorMagnitude(&ds3db.vVelocity) == 0) && (VectorMagnitude(&dsb->device->ds3dl.vVelocity) == 0))
290         {
291                 TRACE("doppler: Buffer and Listener don't have velocities\n");
292         }
293         else
294         {
295                 /* calculate length of ds3db.vVelocity component which causes Doppler Effect
296                    NOTE: if buffer moves TOWARDS the listener, it's velocity component is NEGATIVE
297                          if buffer moves AWAY from listener, it's velocity component is POSITIVE */
298                 flBufferVel = ProjectVector(&dsb->ds3db_ds3db.vVelocity, &vDistance);
299                 /* calculate length of ds3dl.vVelocity component which causes Doppler Effect
300                    NOTE: if listener moves TOWARDS the buffer, it's velocity component is POSITIVE
301                          if listener moves AWAY from buffer, it's velocity component is NEGATIVE */
302                 flListenerVel = ProjectVector(&dsb->device->ds3dl.vVelocity, &vDistance);
303                 /* formula taken from Gianicoli D.: Physics, 4th edition: */
304                 /* FIXME: replace dsb->freq with appropriate frequency ! */
305                 flFreq = dsb->freq * ((DEFAULT_VELOCITY + flListenerVel)/(DEFAULT_VELOCITY + flBufferVel));
306                 TRACE("doppler: Buffer velocity (component) = %lf, Listener velocity (component) = %lf => Doppler shift: %ld Hz -> %lf Hz\n", flBufferVel, flListenerVel,
307                       dsb->freq, flFreq);
308                 /* FIXME: replace following line with correct frequency setting ! */
309                 dsb->freq = flFreq;
310         }
311 #endif  
312         
313         /* time for remix */
314         DSOUND_RecalcVolPan(&dsb->volpan);
315 }
316
317 static void DSOUND_Mix3DBuffer(IDirectSoundBufferImpl *dsb)
318 {
319         TRACE("(%p)\n",dsb);
320
321         DSOUND_Calc3DBuffer(dsb);
322         DSOUND_ForceRemix(dsb);                 
323 }
324
325 static void DSOUND_ChangeListener(IDirectSound3DListenerImpl *ds3dl)
326 {
327         int i;
328         TRACE("(%p)\n",ds3dl);
329         for (i = 0; i < ds3dl->device->nrofbuffers; i++)
330         {
331                 /* some buffers don't have 3d buffer (Ultima IX seems to
332                 crash without the following line) */
333                 if (ds3dl->device->buffers[i]->ds3db == NULL)
334                         continue;
335                 if (ds3dl->device->buffers[i]->ds3db_need_recalc)
336                 {
337                         DSOUND_Mix3DBuffer(ds3dl->device->buffers[i]);
338                 }
339         }
340 }
341
342 /*******************************************************************************
343  *              IDirectSound3DBuffer
344  */
345
346 /* IUnknown methods */
347 static HRESULT WINAPI IDirectSound3DBufferImpl_QueryInterface(
348         LPDIRECTSOUND3DBUFFER iface, REFIID riid, LPVOID *ppobj)
349 {
350         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
351
352         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
353         return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb, riid, ppobj);
354 }
355
356 static ULONG WINAPI IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface)
357 {
358     IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
359     ULONG ref = InterlockedIncrement(&(This->ref));
360     TRACE("(%p) ref was %d\n", This, ref - 1);
361     return ref;
362 }
363
364 static ULONG WINAPI IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface)
365 {
366     IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
367     ULONG ref = InterlockedDecrement(&(This->ref));
368     TRACE("(%p) ref was %d\n", This, ref + 1);
369
370     if (!ref) {
371         This->dsb->ds3db = NULL;
372         IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
373         HeapFree(GetProcessHeap(), 0, This);
374         TRACE("(%p) released\n", This);
375     }
376     return ref;
377 }
378
379 /* IDirectSound3DBuffer methods */
380 static HRESULT WINAPI IDirectSound3DBufferImpl_GetAllParameters(
381         LPDIRECTSOUND3DBUFFER iface,
382         LPDS3DBUFFER lpDs3dBuffer)
383 {
384         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
385         TRACE("(%p,%p)\n",This,lpDs3dBuffer);
386
387         if (lpDs3dBuffer == NULL) {
388                 WARN("invalid parameter: lpDs3dBuffer == NULL\n");
389                 return DSERR_INVALIDPARAM;
390         }
391
392         if (lpDs3dBuffer->dwSize < sizeof(*lpDs3dBuffer)) {
393                 WARN("invalid parameter: lpDs3dBuffer->dwSize = %d\n",lpDs3dBuffer->dwSize);
394                 return DSERR_INVALIDPARAM;
395         }
396         
397         TRACE("returning: all parameters\n");
398         *lpDs3dBuffer = This->dsb->ds3db_ds3db;
399         return DS_OK;
400 }
401
402 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeAngles(
403         LPDIRECTSOUND3DBUFFER iface,
404         LPDWORD lpdwInsideConeAngle,
405         LPDWORD lpdwOutsideConeAngle)
406 {
407         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
408         TRACE("returning: Inside Cone Angle = %d degrees; Outside Cone Angle = %d degrees\n",
409                 This->dsb->ds3db_ds3db.dwInsideConeAngle, This->dsb->ds3db_ds3db.dwOutsideConeAngle);
410         *lpdwInsideConeAngle = This->dsb->ds3db_ds3db.dwInsideConeAngle;
411         *lpdwOutsideConeAngle = This->dsb->ds3db_ds3db.dwOutsideConeAngle;
412         return DS_OK;
413 }
414
415 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOrientation(
416         LPDIRECTSOUND3DBUFFER iface,
417         LPD3DVECTOR lpvConeOrientation)
418 {
419         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
420         TRACE("returning: Cone Orientation vector = (%f,%f,%f)\n",
421                 This->dsb->ds3db_ds3db.vConeOrientation.x,
422                 This->dsb->ds3db_ds3db.vConeOrientation.y,
423                 This->dsb->ds3db_ds3db.vConeOrientation.z);
424         *lpvConeOrientation = This->dsb->ds3db_ds3db.vConeOrientation;
425         return DS_OK;
426 }
427
428 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOutsideVolume(
429         LPDIRECTSOUND3DBUFFER iface,
430         LPLONG lplConeOutsideVolume)
431 {
432         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
433         TRACE("returning: Cone Outside Volume = %d\n", This->dsb->ds3db_ds3db.lConeOutsideVolume);
434         *lplConeOutsideVolume = This->dsb->ds3db_ds3db.lConeOutsideVolume;
435         return DS_OK;
436 }
437
438 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMaxDistance(
439         LPDIRECTSOUND3DBUFFER iface,
440         LPD3DVALUE lpfMaxDistance)
441 {
442         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
443         TRACE("returning: Max Distance = %f\n", This->dsb->ds3db_ds3db.flMaxDistance);
444         *lpfMaxDistance = This->dsb->ds3db_ds3db.flMaxDistance;
445         return DS_OK;
446 }
447
448 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMinDistance(
449         LPDIRECTSOUND3DBUFFER iface,
450         LPD3DVALUE lpfMinDistance)
451 {
452         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
453         TRACE("returning: Min Distance = %f\n", This->dsb->ds3db_ds3db.flMinDistance);
454         *lpfMinDistance = This->dsb->ds3db_ds3db.flMinDistance;
455         return DS_OK;
456 }
457
458 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMode(
459         LPDIRECTSOUND3DBUFFER iface,
460         LPDWORD lpdwMode)
461 {
462         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
463         TRACE("returning: Mode = %d\n", This->dsb->ds3db_ds3db.dwMode);
464         *lpdwMode = This->dsb->ds3db_ds3db.dwMode;
465         return DS_OK;
466 }
467
468 static HRESULT WINAPI IDirectSound3DBufferImpl_GetPosition(
469         LPDIRECTSOUND3DBUFFER iface,
470         LPD3DVECTOR lpvPosition)
471 {
472         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
473         TRACE("returning: Position vector = (%f,%f,%f)\n",
474                 This->dsb->ds3db_ds3db.vPosition.x,
475                 This->dsb->ds3db_ds3db.vPosition.y,
476                 This->dsb->ds3db_ds3db.vPosition.z);
477         *lpvPosition = This->dsb->ds3db_ds3db.vPosition;
478         return DS_OK;
479 }
480
481 static HRESULT WINAPI IDirectSound3DBufferImpl_GetVelocity(
482         LPDIRECTSOUND3DBUFFER iface,
483         LPD3DVECTOR lpvVelocity)
484 {
485         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
486         TRACE("returning: Velocity vector = (%f,%f,%f)\n",
487                 This->dsb->ds3db_ds3db.vVelocity.x,
488                 This->dsb->ds3db_ds3db.vVelocity.y,
489                 This->dsb->ds3db_ds3db.vVelocity.z);
490         *lpvVelocity = This->dsb->ds3db_ds3db.vVelocity;
491         return DS_OK;
492 }
493
494 static HRESULT WINAPI IDirectSound3DBufferImpl_SetAllParameters(
495         LPDIRECTSOUND3DBUFFER iface,
496         LPCDS3DBUFFER lpcDs3dBuffer,
497         DWORD dwApply)
498 {
499         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
500         DWORD status = DSERR_INVALIDPARAM;
501         TRACE("(%p,%p,%x)\n",iface,lpcDs3dBuffer,dwApply);
502
503         if (lpcDs3dBuffer == NULL) {
504                 WARN("invalid parameter: lpcDs3dBuffer == NULL\n");
505                 return status;
506         }
507
508         if (lpcDs3dBuffer->dwSize != sizeof(DS3DBUFFER)) {
509                 WARN("invalid parameter: lpcDs3dBuffer->dwSize = %d\n", lpcDs3dBuffer->dwSize);
510                 return status;
511         }
512
513         TRACE("setting: all parameters; dwApply = %d\n", dwApply);
514         This->dsb->ds3db_ds3db = *lpcDs3dBuffer;
515
516         if (dwApply == DS3D_IMMEDIATE)
517         {
518                 DSOUND_Mix3DBuffer(This->dsb);
519         }
520         This->dsb->ds3db_need_recalc = TRUE;
521         status = DS_OK;
522
523         return status;
524 }
525
526 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeAngles(
527         LPDIRECTSOUND3DBUFFER iface,
528         DWORD dwInsideConeAngle,
529         DWORD dwOutsideConeAngle,
530         DWORD dwApply)
531 {
532         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
533         TRACE("setting: Inside Cone Angle = %d; Outside Cone Angle = %d; dwApply = %d\n",
534                 dwInsideConeAngle, dwOutsideConeAngle, dwApply);
535         This->dsb->ds3db_ds3db.dwInsideConeAngle = dwInsideConeAngle;
536         This->dsb->ds3db_ds3db.dwOutsideConeAngle = dwOutsideConeAngle;
537         if (dwApply == DS3D_IMMEDIATE)
538         {
539                 DSOUND_Mix3DBuffer(This->dsb);
540         }
541         This->dsb->ds3db_need_recalc = TRUE;
542         return DS_OK;
543 }
544
545 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOrientation(
546         LPDIRECTSOUND3DBUFFER iface,
547         D3DVALUE x, D3DVALUE y, D3DVALUE z,
548         DWORD dwApply)
549 {
550         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
551         TRACE("setting: Cone Orientation vector = (%f,%f,%f); dwApply = %d\n", x, y, z, dwApply);
552         This->dsb->ds3db_ds3db.vConeOrientation.x = x;
553         This->dsb->ds3db_ds3db.vConeOrientation.y = y;
554         This->dsb->ds3db_ds3db.vConeOrientation.z = z;
555         if (dwApply == DS3D_IMMEDIATE)
556         {
557                 This->dsb->ds3db_need_recalc = FALSE;
558                 DSOUND_Mix3DBuffer(This->dsb);
559         }
560         This->dsb->ds3db_need_recalc = TRUE;
561         return DS_OK;
562 }
563
564 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOutsideVolume(
565         LPDIRECTSOUND3DBUFFER iface,
566         LONG lConeOutsideVolume,
567         DWORD dwApply)
568 {
569         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
570         TRACE("setting: ConeOutsideVolume = %d; dwApply = %d\n", lConeOutsideVolume, dwApply);
571         This->dsb->ds3db_ds3db.lConeOutsideVolume = lConeOutsideVolume;
572         if (dwApply == DS3D_IMMEDIATE)
573         {
574                 This->dsb->ds3db_need_recalc = FALSE;
575                 DSOUND_Mix3DBuffer(This->dsb);
576         }
577         This->dsb->ds3db_need_recalc = TRUE;
578         return DS_OK;
579 }
580
581 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMaxDistance(
582         LPDIRECTSOUND3DBUFFER iface,
583         D3DVALUE fMaxDistance,
584         DWORD dwApply)
585 {
586         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
587         TRACE("setting: MaxDistance = %f; dwApply = %d\n", fMaxDistance, dwApply);
588         This->dsb->ds3db_ds3db.flMaxDistance = fMaxDistance;
589         if (dwApply == DS3D_IMMEDIATE)
590         {
591                 This->dsb->ds3db_need_recalc = FALSE;
592                 DSOUND_Mix3DBuffer(This->dsb);
593         }
594         This->dsb->ds3db_need_recalc = TRUE;
595         return DS_OK;
596 }
597
598 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMinDistance(
599         LPDIRECTSOUND3DBUFFER iface,
600         D3DVALUE fMinDistance,
601         DWORD dwApply)
602 {
603         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
604         TRACE("setting: MinDistance = %f; dwApply = %d\n", fMinDistance, dwApply);
605         This->dsb->ds3db_ds3db.flMinDistance = fMinDistance;
606         if (dwApply == DS3D_IMMEDIATE)
607         {
608                 This->dsb->ds3db_need_recalc = FALSE;
609                 DSOUND_Mix3DBuffer(This->dsb);
610         }
611         This->dsb->ds3db_need_recalc = TRUE;
612         return DS_OK;
613 }
614
615 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMode(
616         LPDIRECTSOUND3DBUFFER iface,
617         DWORD dwMode,
618         DWORD dwApply)
619 {
620         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
621         TRACE("setting: Mode = %d; dwApply = %d\n", dwMode, dwApply);
622         This->dsb->ds3db_ds3db.dwMode = dwMode;
623         if (dwApply == DS3D_IMMEDIATE)
624         {
625                 This->dsb->ds3db_need_recalc = FALSE;
626                 DSOUND_Mix3DBuffer(This->dsb);
627         }
628         This->dsb->ds3db_need_recalc = TRUE;
629         return DS_OK;
630 }
631
632 static HRESULT WINAPI IDirectSound3DBufferImpl_SetPosition(
633         LPDIRECTSOUND3DBUFFER iface,
634         D3DVALUE x, D3DVALUE y, D3DVALUE z,
635         DWORD dwApply)
636 {
637         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
638         TRACE("setting: Position vector = (%f,%f,%f); dwApply = %d\n", x, y, z, dwApply);
639         This->dsb->ds3db_ds3db.vPosition.x = x;
640         This->dsb->ds3db_ds3db.vPosition.y = y;
641         This->dsb->ds3db_ds3db.vPosition.z = z;
642         if (dwApply == DS3D_IMMEDIATE)
643         {
644                 This->dsb->ds3db_need_recalc = FALSE;
645                 DSOUND_Mix3DBuffer(This->dsb);
646         }
647         This->dsb->ds3db_need_recalc = TRUE;
648         return DS_OK;
649 }
650
651 static HRESULT WINAPI IDirectSound3DBufferImpl_SetVelocity(
652         LPDIRECTSOUND3DBUFFER iface,
653         D3DVALUE x, D3DVALUE y, D3DVALUE z,
654         DWORD dwApply)
655 {
656         IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface;
657         TRACE("setting: Velocity vector = (%f,%f,%f); dwApply = %d\n", x, y, z, dwApply);
658         This->dsb->ds3db_ds3db.vVelocity.x = x;
659         This->dsb->ds3db_ds3db.vVelocity.y = y;
660         This->dsb->ds3db_ds3db.vVelocity.z = z;
661         if (dwApply == DS3D_IMMEDIATE)
662         {
663                 This->dsb->ds3db_need_recalc = FALSE;
664                 DSOUND_Mix3DBuffer(This->dsb);
665         }
666         This->dsb->ds3db_need_recalc = TRUE;
667         return DS_OK;
668 }
669
670 static const IDirectSound3DBufferVtbl ds3dbvt =
671 {
672         /* IUnknown methods */
673         IDirectSound3DBufferImpl_QueryInterface,
674         IDirectSound3DBufferImpl_AddRef,
675         IDirectSound3DBufferImpl_Release,
676         /* IDirectSound3DBuffer methods */
677         IDirectSound3DBufferImpl_GetAllParameters,
678         IDirectSound3DBufferImpl_GetConeAngles,
679         IDirectSound3DBufferImpl_GetConeOrientation,
680         IDirectSound3DBufferImpl_GetConeOutsideVolume,
681         IDirectSound3DBufferImpl_GetMaxDistance,
682         IDirectSound3DBufferImpl_GetMinDistance,
683         IDirectSound3DBufferImpl_GetMode,
684         IDirectSound3DBufferImpl_GetPosition,
685         IDirectSound3DBufferImpl_GetVelocity,
686         IDirectSound3DBufferImpl_SetAllParameters,
687         IDirectSound3DBufferImpl_SetConeAngles,
688         IDirectSound3DBufferImpl_SetConeOrientation,
689         IDirectSound3DBufferImpl_SetConeOutsideVolume,
690         IDirectSound3DBufferImpl_SetMaxDistance,
691         IDirectSound3DBufferImpl_SetMinDistance,
692         IDirectSound3DBufferImpl_SetMode,
693         IDirectSound3DBufferImpl_SetPosition,
694         IDirectSound3DBufferImpl_SetVelocity,
695 };
696
697 HRESULT IDirectSound3DBufferImpl_Create(
698         IDirectSoundBufferImpl *dsb,
699         IDirectSound3DBufferImpl **pds3db)
700 {
701         IDirectSound3DBufferImpl *ds3db;
702         TRACE("(%p,%p)\n",dsb,pds3db);
703
704         ds3db = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*ds3db));
705
706         if (ds3db == NULL) {
707                 WARN("out of memory\n");
708                 *pds3db = 0;
709                 return DSERR_OUTOFMEMORY;
710         }
711
712         ds3db->ref = 0;
713         ds3db->dsb = dsb;
714         ds3db->lpVtbl = &ds3dbvt;
715
716         ds3db->dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
717         ds3db->dsb->ds3db_ds3db.vPosition.x = 0.0;
718         ds3db->dsb->ds3db_ds3db.vPosition.y = 0.0;
719         ds3db->dsb->ds3db_ds3db.vPosition.z = 0.0;
720         ds3db->dsb->ds3db_ds3db.vVelocity.x = 0.0;
721         ds3db->dsb->ds3db_ds3db.vVelocity.y = 0.0;
722         ds3db->dsb->ds3db_ds3db.vVelocity.z = 0.0;
723         ds3db->dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
724         ds3db->dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
725         ds3db->dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
726         ds3db->dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
727         ds3db->dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
728         ds3db->dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
729         ds3db->dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
730         ds3db->dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
731         ds3db->dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
732
733         ds3db->dsb->ds3db_need_recalc = TRUE;
734
735         IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
736
737         *pds3db = ds3db;
738         return S_OK;
739 }
740
741 HRESULT IDirectSound3DBufferImpl_Destroy(
742     IDirectSound3DBufferImpl *pds3db)
743 {
744     TRACE("(%p)\n",pds3db);
745
746     while (IDirectSound3DBufferImpl_Release((LPDIRECTSOUND3DBUFFER)pds3db) > 0);
747
748     return S_OK;
749 }
750
751 /*******************************************************************************
752  *            IDirectSound3DListener
753  */
754
755 /* IUnknown methods */
756 static HRESULT WINAPI IDirectSound3DListenerImpl_QueryInterface(
757         LPDIRECTSOUND3DLISTENER iface, REFIID riid, LPVOID *ppobj)
758 {
759         IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
760
761         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
762
763         if (ppobj == NULL) {
764                 WARN("invalid parameter\n");
765                 return E_INVALIDARG;
766         }
767
768         *ppobj = NULL;  /* assume failure */
769
770         if ( IsEqualGUID(riid, &IID_IUnknown) ||
771              IsEqualGUID(riid, &IID_IDirectSound3DListener ) ) {
772                 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)This);
773                 *ppobj = This;
774                 return S_OK;
775         }
776
777         if ( IsEqualGUID(riid, &IID_IDirectSoundBuffer) ) {
778                 if (!This->device->primary)
779                         PrimaryBufferImpl_Create(This->device, &(This->device->primary), &(This->device->dsbd));
780                 if (This->device->primary) {
781                         *ppobj = This->device->primary;
782                         IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)*ppobj);
783                         return S_OK;
784                 }
785         }
786
787         FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
788         return E_NOINTERFACE;
789 }
790
791 static ULONG WINAPI IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface)
792 {
793     IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
794     ULONG ref = InterlockedIncrement(&(This->ref));
795     TRACE("(%p) ref was %d\n", This, ref - 1);
796     return ref;
797 }
798
799 static ULONG WINAPI IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface)
800 {
801     IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
802     ULONG ref = InterlockedDecrement(&(This->ref));
803     TRACE("(%p) ref was %d\n", This, ref + 1);
804
805     if (!ref) {
806         This->device->listener = 0;
807         HeapFree(GetProcessHeap(), 0, This);
808         TRACE("(%p) released\n", This);
809     }
810     return ref;
811 }
812
813 /* IDirectSound3DListener methods */
814 static HRESULT WINAPI IDirectSound3DListenerImpl_GetAllParameter(
815         LPDIRECTSOUND3DLISTENER iface,
816         LPDS3DLISTENER lpDS3DL)
817 {
818         IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
819         TRACE("(%p,%p)\n",This,lpDS3DL);
820
821         if (lpDS3DL == NULL) {
822                 WARN("invalid parameter: lpDS3DL == NULL\n");
823                 return DSERR_INVALIDPARAM;
824         }
825
826         if (lpDS3DL->dwSize < sizeof(*lpDS3DL)) {
827                 WARN("invalid parameter: lpDS3DL->dwSize = %d\n",lpDS3DL->dwSize);
828                 return DSERR_INVALIDPARAM;
829         }
830         
831         TRACE("returning: all parameters\n");
832         *lpDS3DL = This->device->ds3dl;
833         return DS_OK;
834 }
835
836 static HRESULT WINAPI IDirectSound3DListenerImpl_GetDistanceFactor(
837         LPDIRECTSOUND3DLISTENER iface,
838         LPD3DVALUE lpfDistanceFactor)
839 {
840         IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
841         TRACE("returning: Distance Factor = %f\n", This->device->ds3dl.flDistanceFactor);
842         *lpfDistanceFactor = This->device->ds3dl.flDistanceFactor;
843         return DS_OK;
844 }
845
846 static HRESULT WINAPI IDirectSound3DListenerImpl_GetDopplerFactor(
847         LPDIRECTSOUND3DLISTENER iface,
848         LPD3DVALUE lpfDopplerFactor)
849 {
850         IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
851         TRACE("returning: Doppler Factor = %f\n", This->device->ds3dl.flDopplerFactor);
852         *lpfDopplerFactor = This->device->ds3dl.flDopplerFactor;
853         return DS_OK;
854 }
855
856 static HRESULT WINAPI IDirectSound3DListenerImpl_GetOrientation(
857         LPDIRECTSOUND3DLISTENER iface,
858         LPD3DVECTOR lpvOrientFront,
859         LPD3DVECTOR lpvOrientTop)
860 {
861         IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
862         TRACE("returning: OrientFront vector = (%f,%f,%f); OrientTop vector = (%f,%f,%f)\n", This->device->ds3dl.vOrientFront.x,
863         This->device->ds3dl.vOrientFront.y, This->device->ds3dl.vOrientFront.z, This->device->ds3dl.vOrientTop.x, This->device->ds3dl.vOrientTop.y,
864         This->device->ds3dl.vOrientTop.z);
865         *lpvOrientFront = This->device->ds3dl.vOrientFront;
866         *lpvOrientTop = This->device->ds3dl.vOrientTop;
867         return DS_OK;
868 }
869
870 static HRESULT WINAPI IDirectSound3DListenerImpl_GetPosition(
871         LPDIRECTSOUND3DLISTENER iface,
872         LPD3DVECTOR lpvPosition)
873 {
874         IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
875         TRACE("returning: Position vector = (%f,%f,%f)\n", This->device->ds3dl.vPosition.x, This->device->ds3dl.vPosition.y, This->device->ds3dl.vPosition.z);
876         *lpvPosition = This->device->ds3dl.vPosition;
877         return DS_OK;
878 }
879
880 static HRESULT WINAPI IDirectSound3DListenerImpl_GetRolloffFactor(
881         LPDIRECTSOUND3DLISTENER iface,
882         LPD3DVALUE lpfRolloffFactor)
883 {
884         IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
885         TRACE("returning: RolloffFactor = %f\n", This->device->ds3dl.flRolloffFactor);
886         *lpfRolloffFactor = This->device->ds3dl.flRolloffFactor;
887         return DS_OK;
888 }
889
890 static HRESULT WINAPI IDirectSound3DListenerImpl_GetVelocity(
891         LPDIRECTSOUND3DLISTENER iface,
892         LPD3DVECTOR lpvVelocity)
893 {
894         IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
895         TRACE("returning: Velocity vector = (%f,%f,%f)\n", This->device->ds3dl.vVelocity.x, This->device->ds3dl.vVelocity.y, This->device->ds3dl.vVelocity.z);
896         *lpvVelocity = This->device->ds3dl.vVelocity;
897         return DS_OK;
898 }
899
900 static HRESULT WINAPI IDirectSound3DListenerImpl_SetAllParameters(
901         LPDIRECTSOUND3DLISTENER iface,
902         LPCDS3DLISTENER lpcDS3DL,
903         DWORD dwApply)
904 {
905         IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
906         TRACE("setting: all parameters; dwApply = %d\n", dwApply);
907         This->device->ds3dl = *lpcDS3DL;
908         if (dwApply == DS3D_IMMEDIATE)
909         {
910                 This->device->ds3dl_need_recalc = FALSE;
911                 DSOUND_ChangeListener(This);
912         }
913         This->device->ds3dl_need_recalc = TRUE;
914         return DS_OK;
915 }
916
917 static HRESULT WINAPI IDirectSound3DListenerImpl_SetDistanceFactor(
918         LPDIRECTSOUND3DLISTENER iface,
919         D3DVALUE fDistanceFactor,
920         DWORD dwApply)
921 {
922         IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
923         TRACE("setting: Distance Factor = %f; dwApply = %d\n", fDistanceFactor, dwApply);
924         This->device->ds3dl.flDistanceFactor = fDistanceFactor;
925         if (dwApply == DS3D_IMMEDIATE)
926         {
927                 This->device->ds3dl_need_recalc = FALSE;
928                 DSOUND_ChangeListener(This);
929         }
930         This->device->ds3dl_need_recalc = TRUE;
931         return DS_OK;
932 }
933
934 static HRESULT WINAPI IDirectSound3DListenerImpl_SetDopplerFactor(
935         LPDIRECTSOUND3DLISTENER iface,
936         D3DVALUE fDopplerFactor,
937         DWORD dwApply)
938 {
939         IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
940         TRACE("setting: Doppler Factor = %f; dwApply = %d\n", fDopplerFactor, dwApply);
941         This->device->ds3dl.flDopplerFactor = fDopplerFactor;
942         if (dwApply == DS3D_IMMEDIATE)
943         {
944                 This->device->ds3dl_need_recalc = FALSE;
945                 DSOUND_ChangeListener(This);
946         }
947         This->device->ds3dl_need_recalc = TRUE;
948         return DS_OK;
949 }
950
951 static HRESULT WINAPI IDirectSound3DListenerImpl_SetOrientation(
952         LPDIRECTSOUND3DLISTENER iface,
953         D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront,
954         D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop,
955         DWORD dwApply)
956 {
957         IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
958         TRACE("setting: Front vector = (%f,%f,%f); Top vector = (%f,%f,%f); dwApply = %d\n",
959         xFront, yFront, zFront, xTop, yTop, zTop, dwApply);
960         This->device->ds3dl.vOrientFront.x = xFront;
961         This->device->ds3dl.vOrientFront.y = yFront;
962         This->device->ds3dl.vOrientFront.z = zFront;
963         This->device->ds3dl.vOrientTop.x = xTop;
964         This->device->ds3dl.vOrientTop.y = yTop;
965         This->device->ds3dl.vOrientTop.z = zTop;
966         if (dwApply == DS3D_IMMEDIATE)
967         {
968                 This->device->ds3dl_need_recalc = FALSE;
969                 DSOUND_ChangeListener(This);
970         }
971         This->device->ds3dl_need_recalc = TRUE;
972         return DS_OK;
973 }
974
975 static HRESULT WINAPI IDirectSound3DListenerImpl_SetPosition(
976         LPDIRECTSOUND3DLISTENER iface,
977         D3DVALUE x, D3DVALUE y, D3DVALUE z,
978         DWORD dwApply)
979 {
980         IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
981         TRACE("setting: Position vector = (%f,%f,%f); dwApply = %d\n", x, y, z, dwApply);
982         This->device->ds3dl.vPosition.x = x;
983         This->device->ds3dl.vPosition.y = y;
984         This->device->ds3dl.vPosition.z = z;
985         if (dwApply == DS3D_IMMEDIATE)
986         {
987                 This->device->ds3dl_need_recalc = FALSE;
988                 DSOUND_ChangeListener(This);
989         }
990         This->device->ds3dl_need_recalc = TRUE;
991         return DS_OK;
992 }
993
994 static HRESULT WINAPI IDirectSound3DListenerImpl_SetRolloffFactor(
995         LPDIRECTSOUND3DLISTENER iface,
996         D3DVALUE fRolloffFactor,
997         DWORD dwApply)
998 {
999         IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
1000         TRACE("setting: Rolloff Factor = %f; dwApply = %d\n", fRolloffFactor, dwApply);
1001         This->device->ds3dl.flRolloffFactor = fRolloffFactor;
1002         if (dwApply == DS3D_IMMEDIATE)
1003         {
1004                 This->device->ds3dl_need_recalc = FALSE;
1005                 DSOUND_ChangeListener(This);
1006         }
1007         This->device->ds3dl_need_recalc = TRUE;
1008         return DS_OK;
1009 }
1010
1011 static HRESULT WINAPI IDirectSound3DListenerImpl_SetVelocity(
1012         LPDIRECTSOUND3DLISTENER iface,
1013         D3DVALUE x, D3DVALUE y, D3DVALUE z,
1014         DWORD dwApply)
1015 {
1016         IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
1017         TRACE("setting: Velocity vector = (%f,%f,%f); dwApply = %d\n", x, y, z, dwApply);
1018         This->device->ds3dl.vVelocity.x = x;
1019         This->device->ds3dl.vVelocity.y = y;
1020         This->device->ds3dl.vVelocity.z = z;
1021         if (dwApply == DS3D_IMMEDIATE)
1022         {
1023                 This->device->ds3dl_need_recalc = FALSE;
1024                 DSOUND_ChangeListener(This);
1025         }
1026         This->device->ds3dl_need_recalc = TRUE;
1027         return DS_OK;
1028 }
1029
1030 static HRESULT WINAPI IDirectSound3DListenerImpl_CommitDeferredSettings(
1031         LPDIRECTSOUND3DLISTENER iface)
1032 {
1033         IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface;
1034         TRACE("\n");
1035         DSOUND_ChangeListener(This);
1036         return DS_OK;
1037 }
1038
1039 static const IDirectSound3DListenerVtbl ds3dlvt =
1040 {
1041         /* IUnknown methods */
1042         IDirectSound3DListenerImpl_QueryInterface,
1043         IDirectSound3DListenerImpl_AddRef,
1044         IDirectSound3DListenerImpl_Release,
1045         /* IDirectSound3DListener methods */
1046         IDirectSound3DListenerImpl_GetAllParameter,
1047         IDirectSound3DListenerImpl_GetDistanceFactor,
1048         IDirectSound3DListenerImpl_GetDopplerFactor,
1049         IDirectSound3DListenerImpl_GetOrientation,
1050         IDirectSound3DListenerImpl_GetPosition,
1051         IDirectSound3DListenerImpl_GetRolloffFactor,
1052         IDirectSound3DListenerImpl_GetVelocity,
1053         IDirectSound3DListenerImpl_SetAllParameters,
1054         IDirectSound3DListenerImpl_SetDistanceFactor,
1055         IDirectSound3DListenerImpl_SetDopplerFactor,
1056         IDirectSound3DListenerImpl_SetOrientation,
1057         IDirectSound3DListenerImpl_SetPosition,
1058         IDirectSound3DListenerImpl_SetRolloffFactor,
1059         IDirectSound3DListenerImpl_SetVelocity,
1060         IDirectSound3DListenerImpl_CommitDeferredSettings,
1061 };
1062
1063 HRESULT IDirectSound3DListenerImpl_Create(
1064         DirectSoundDevice * device,
1065         IDirectSound3DListenerImpl ** ppdsl)
1066 {
1067         IDirectSound3DListenerImpl *pdsl;
1068         TRACE("(%p,%p)\n",device,ppdsl);
1069
1070         pdsl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*pdsl));
1071
1072         if (pdsl == NULL) {
1073                 WARN("out of memory\n");
1074                 *ppdsl = 0;
1075                 return DSERR_OUTOFMEMORY;
1076         }
1077
1078         pdsl->ref = 0;
1079         pdsl->lpVtbl = &ds3dlvt;
1080
1081         pdsl->device = device;
1082
1083         pdsl->device->ds3dl.dwSize = sizeof(DS3DLISTENER);
1084         pdsl->device->ds3dl.vPosition.x = 0.0;
1085         pdsl->device->ds3dl.vPosition.y = 0.0;
1086         pdsl->device->ds3dl.vPosition.z = 0.0;
1087         pdsl->device->ds3dl.vVelocity.x = 0.0;
1088         pdsl->device->ds3dl.vVelocity.y = 0.0;
1089         pdsl->device->ds3dl.vVelocity.z = 0.0;
1090         pdsl->device->ds3dl.vOrientFront.x = 0.0;
1091         pdsl->device->ds3dl.vOrientFront.y = 0.0;
1092         pdsl->device->ds3dl.vOrientFront.z = 1.0;
1093         pdsl->device->ds3dl.vOrientTop.x = 0.0;
1094         pdsl->device->ds3dl.vOrientTop.y = 1.0;
1095         pdsl->device->ds3dl.vOrientTop.z = 0.0;
1096         pdsl->device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
1097         pdsl->device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
1098         pdsl->device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
1099
1100         pdsl->device->ds3dl_need_recalc = TRUE;
1101
1102         *ppdsl = pdsl;
1103         return S_OK;
1104 }