ok() does not support '%S'. Store the Ansi version, convert to Unicode
[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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 "config.h"
41 #include <assert.h>
42 #include <stdio.h>
43 #include <sys/types.h>
44 #include <sys/fcntl.h>
45 #ifdef HAVE_UNISTD_H
46 # include <unistd.h>
47 #endif
48 #include <stdlib.h>
49 #include <string.h>
50 #include <math.h>       /* Insomnia - pow() function */
51
52 #define NONAMELESSUNION
53 #define NONAMELESSSTRUCT
54 #include "windef.h"
55 #include "winbase.h"
56 #include "wingdi.h"
57 #include "winuser.h"
58 #include "winerror.h"
59 #include "mmsystem.h"
60 #include "winternl.h"
61 #include "mmddk.h"
62 #include "wine/windef16.h"
63 #include "wine/debug.h"
64 #include "dsound.h"
65 #include "dsdriver.h"
66 #include "dsound_private.h"
67
68 WINE_DEFAULT_DEBUG_CHANNEL(dsound3d);
69
70 /*******************************************************************************
71  *              Auxiliary functions
72  */
73
74 /* scalar product (i believe it's called dot product in english) */
75 static inline D3DVALUE ScalarProduct (LPD3DVECTOR a, LPD3DVECTOR b)
76 {
77         D3DVALUE c;
78         c = (a->u1.x*b->u1.x) + (a->u2.y*b->u2.y) + (a->u3.z*b->u3.z);
79         TRACE("(%f,%f,%f) * (%f,%f,%f) = %f)\n", a->u1.x, a->u2.y, a->u3.z, b->u1.x, b->u2.y, \
80               b->u3.z, c);
81         return c;
82 }
83
84 /* vector product (i believe it's called cross product in english */
85 static inline LPD3DVECTOR VectorProduct (LPD3DVECTOR a, LPD3DVECTOR b)
86 {
87         LPD3DVECTOR c;
88         c->u1.x = (a->u2.y*b->u3.z) - (a->u3.z*b->u2.y);
89         c->u2.y = (a->u3.z*b->u1.x) - (a->u1.x*b->u3.z);
90         c->u3.z = (a->u1.x*b->u2.y) - (a->u2.y*b->u1.x);
91         TRACE("(%f,%f,%f) x (%f,%f,%f) = (%f,%f,%f)\n", a->u1.x, a->u2.y, a->u3.z, b->u1.x, b->u2.y, \
92               b->u3.z, c->u1.x, c->u2.y, c->u3.z);
93         return c;
94 }
95
96 /* magnitude (lenght) of vector */
97 static inline D3DVALUE VectorMagnitude (LPD3DVECTOR a)
98 {
99         D3DVALUE l;
100         l = sqrt (ScalarProduct (a, a));
101         TRACE("|(%f,%f,%f)| = %f\n", a->u1.x, a->u2.y, a->u3.z, l);
102         return l;
103 }
104
105 /* conversion between radians and degrees */
106 static inline DWORD RadToDeg (DWORD angle)
107 {
108         DWORD newangle;
109         newangle = angle * (360/(2*M_PI));
110         TRACE("%ld rad = %ld deg\n", angle, newangle);
111         return newangle;
112 }
113
114 /* conversion between degrees and radians */
115 static inline DWORD DegToRad (DWORD angle)
116 {
117         DWORD newangle;
118         newangle = angle * (2*M_PI/360);
119         TRACE("%ld deg = %ld rad\n", angle, newangle);
120         return newangle;
121 }
122
123 /* angle between vectors */
124 static inline DWORD AngleBetweenVectorsDeg (LPD3DVECTOR a, LPD3DVECTOR b)
125 {
126         DWORD angle, cos;
127         D3DVALUE la, lb, product;
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         /* we now have angle in radians */
134         angle = RadToDeg(cos);
135         TRACE("angle between (%f,%f,%f) and (%f,%f,%f) = %ld degrees\n",  a->u1.x, a->u2.y, a->u3.z, b->u1.x, \
136               b->u2.y, b->u3.z, angle);
137         return angle;   
138 }
139
140 /* calculates vector between two points */
141 static inline D3DVECTOR VectorBetweenTwoPoints (LPD3DVECTOR a, LPD3DVECTOR b)
142 {
143         D3DVECTOR c;
144         c.u1.x = b->u1.x - a->u1.x;
145         c.u2.y = b->u2.y - a->u2.y;
146         c.u3.z = b->u3.z - a->u3.z;
147         TRACE("A (%f,%f,%f), B (%f,%f,%f), AB = (%f,%f,%f)\n", a->u1.x, a->u2.y, a->u3.z, b->u1.x, b->u2.y, \
148               b->u3.z, c.u1.x, c.u2.y, c.u3.z);
149         return c;
150 }
151
152 /*******************************************************************************
153  *              3D Buffer and Listener mixing
154  */
155
156 static void WINAPI DSOUND_Mix3DBuffer(IDirectSound3DBufferImpl *ds3db)
157 {
158         IDirectSound3DListenerImpl *dsl;
159         
160         /* volume, at which the sound will be played after all calcs. */
161         LONG lVolume;
162         /* attuneation (temp variable) */
163         LONG lAttuneation;
164         int iPower;
165         /* stuff for distance related stuff calc. */
166         D3DVECTOR vDistance;
167         D3DVALUE fDistance;
168         
169         /* stuff for cone angle calc. */
170         DWORD dwAlpha, dwTheta, dwInsideConeAngle, dwOutsideConeAngle;
171         D3DVECTOR vConeOrientation;
172         DWORD dwConstVolAng; /* Volume/Angle constant */
173         
174         if (ds3db->dsb->dsound->listener == NULL)
175                 return;
176         
177         dsl = ds3db->dsb->dsound->listener;
178         
179         switch (ds3db->ds3db.dwMode)
180         {
181                 case DS3DMODE_NORMAL:
182                 {
183                         /* initial volume */
184                         lVolume = ds3db->lVolume;
185
186                         /* distance attuneation stuff */
187                         vDistance = VectorBetweenTwoPoints(&ds3db->ds3db.vPosition, &dsl->ds3dl.vPosition);
188                         fDistance = VectorMagnitude (&vDistance);
189                         
190                         if (fDistance > ds3db->ds3db.flMaxDistance)
191                         {
192                                 /* some apps don't want you to hear too distant sounds... */
193                                 if (ds3db->dsb->dsbd.dwFlags & DSBCAPS_MUTE3DATMAXDISTANCE)
194                                 {
195                                         ds3db->dsb->volpan.lVolume = DSBVOLUME_MIN;
196                                         DSOUND_RecalcVolPan (&ds3db->dsb->volpan);              
197                                         /* i guess mixing here would be a waste of power */
198                                         return;
199                                 }
200                                 else
201                                         fDistance = ds3db->ds3db.flMaxDistance;
202                         }
203                         
204                         if (fDistance < ds3db->ds3db.flMinDistance)
205                                 fDistance = ds3db->ds3db.flMinDistance;
206                         
207                         /* the formula my dad and i have figured out after reading msdn info about min/max distance
208                            ...hope it works */
209                         iPower = fDistance/ds3db->ds3db.flMinDistance - 1; /* this sucks, but for unknown reason damn thing works only if you reduce it for 1 */
210                         lAttuneation = (((pow(2, iPower) - 1)*DSBVOLUME_MIN) + lVolume)/pow(2, iPower);
211                         lAttuneation *= dsl->ds3dl.flRolloffFactor; /* attuneation according to rolloff factor */
212                         lAttuneation /= 5; /* i've figured this value wih trying (without it, sound is too quiet */
213                         TRACE ("distance att.: distance = %f, min distance = %f => adjusting volume %ld for attuneation %ld\n", fDistance, ds3db->ds3db.flMinDistance, lVolume, lAttuneation);
214                         lVolume += lAttuneation;
215                         
216                         /* conning */
217                         /* correct me if I'm wrong, but i believe 'D3DVECTORS' used below are only points
218                            between which vectors are yet to be calculated */
219                         vConeOrientation = VectorBetweenTwoPoints(&ds3db->ds3db.vPosition, &ds3db->ds3db.vConeOrientation);
220                         /* I/O ConeAngles are defined in both directions; for comparing, we need only half of their values */
221                         dwOutsideConeAngle = ds3db->ds3db.dwOutsideConeAngle / 2;
222                         dwInsideConeAngle = ds3db->ds3db.dwInsideConeAngle / 2;
223                         dwTheta = AngleBetweenVectorsDeg (&vDistance, &vConeOrientation);
224                         /* actual conning */
225                         if (dwTheta <= dwInsideConeAngle)
226                         {
227                                 lAttuneation = 0;
228                                 TRACE("conning: angle (%ld) < InsideConeAngle (%ld), leaving volume at %ld\n", dwTheta, dwInsideConeAngle, lVolume);
229                         }
230                         if (dwTheta > dwOutsideConeAngle)
231                         {
232                                 /* attuneation is equal to lConeOutsideVolume */
233                                 lAttuneation = ds3db->ds3db.lConeOutsideVolume;
234                                 TRACE("conning: angle (%ld) > OutsideConeAngle (%ld), attuneation = %ld, final volume = %ld\n", dwTheta, dwOutsideConeAngle, \
235                                       ds3db->ds3db.lConeOutsideVolume, lVolume);
236                         }
237                         if (dwTheta > dwInsideConeAngle && dwTheta <= dwOutsideConeAngle)
238                         {
239                                 dwAlpha = dwTheta - dwInsideConeAngle;
240                                 dwConstVolAng = ((lVolume + ds3db->ds3db.lConeOutsideVolume) - lVolume) / (dwOutsideConeAngle - dwInsideConeAngle);
241                                 lAttuneation = dwAlpha*dwConstVolAng;
242                                 TRACE("conning: angle = %ld, attuneation = %ld, final Volume = %ld\n", dwTheta, dwAlpha*dwConstVolAng, lVolume);
243                         }
244                         lVolume += lAttuneation;
245                         TRACE("final volume = %ld\n", lVolume);         
246                         
247                         /* at last, we got the desired volume */
248                         ds3db->dsb->volpan.lVolume = lVolume;
249                         DSOUND_RecalcVolPan (&ds3db->dsb->volpan);
250                         DSOUND_ForceRemix (ds3db->dsb);                 
251                         break;
252                 }
253                 case DS3DMODE_HEADRELATIVE:
254                 case DS3DMODE_DISABLE:
255                         DSOUND_RecalcVolPan (&ds3db->dsb->volpan);
256                         DSOUND_ForceRemix (ds3db->dsb);
257                         break;
258         }
259 }
260
261 static void WINAPI DSOUND_ChangeListener(IDirectSound3DListenerImpl *ds3dl)
262 {
263         int i;
264         for (i = 0; i < ds3dl->dsb->dsound->nrofbuffers; i++)
265         {
266                 /* some buffers don't have 3d buffer (Ultima IX seems to
267                 crash without the following line) */
268                 if (ds3dl->dsb->dsound->buffers[i]->ds3db == NULL)
269                         continue;
270                 if (ds3dl->dsb->dsound->buffers[i]->ds3db->need_recalc == TRUE)
271                 {
272                         DSOUND_Mix3DBuffer(ds3dl->dsb->dsound->buffers[i]->ds3db);
273                 }
274                         
275         }
276 }
277
278 /*******************************************************************************
279  *              IDirectSound3DBuffer
280  */
281
282 /* IUnknown methods */
283 static HRESULT WINAPI IDirectSound3DBufferImpl_QueryInterface(
284         LPDIRECTSOUND3DBUFFER iface, REFIID riid, LPVOID *ppobj)
285 {
286         ICOM_THIS(IDirectSound3DBufferImpl,iface);
287
288         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
289         return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb, riid, ppobj);
290 }
291
292 static ULONG WINAPI IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface)
293 {
294         ICOM_THIS(IDirectSound3DBufferImpl,iface);
295         ULONG ulReturn;
296
297         TRACE("(%p) ref was %ld\n", This, This->ref);
298         ulReturn = InterlockedIncrement(&This->ref);
299         if (ulReturn == 1)
300                 IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This->dsb);
301         return ulReturn;
302 }
303
304 static ULONG WINAPI IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface)
305 {
306         ICOM_THIS(IDirectSound3DBufferImpl,iface);
307         ULONG ulReturn;
308
309         TRACE("(%p) ref was %ld\n", This, This->ref);
310
311         ulReturn = InterlockedDecrement(&This->ref);
312         if(ulReturn)
313                 return ulReturn;
314
315         if (This->dsb) {
316                 BOOL std = (This->dsb->dsbd.dwFlags & DSBCAPS_CTRL3D);
317
318                 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
319
320                 if (std)
321                         return 0; /* leave it to IDirectSoundBufferImpl_Release */
322         }
323
324         if (This->dsb->ds3db == This) This->dsb->ds3db = NULL;
325
326         DeleteCriticalSection(&This->lock);
327
328         HeapFree(GetProcessHeap(),0,This);
329
330         return 0;
331 }
332
333 /* IDirectSound3DBuffer methods */
334 static HRESULT WINAPI IDirectSound3DBufferImpl_GetAllParameters(
335         LPDIRECTSOUND3DBUFFER iface,
336         LPDS3DBUFFER lpDs3dBuffer)
337 {
338         ICOM_THIS(IDirectSound3DBufferImpl,iface);
339         TRACE("returning: all parameters\n");
340         *lpDs3dBuffer = This->ds3db;
341         return DS_OK;
342 }
343
344 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeAngles(
345         LPDIRECTSOUND3DBUFFER iface,
346         LPDWORD lpdwInsideConeAngle,
347         LPDWORD lpdwOutsideConeAngle)
348 {
349         ICOM_THIS(IDirectSound3DBufferImpl,iface);
350         TRACE("returning: Inside Cone Angle = %ld degrees; Outside Cone Angle = %ld degrees\n", This->ds3db.dwInsideConeAngle, This->ds3db.dwOutsideConeAngle);
351         *lpdwInsideConeAngle = This->ds3db.dwInsideConeAngle;
352         *lpdwOutsideConeAngle = This->ds3db.dwOutsideConeAngle;
353         return DS_OK;
354 }
355
356 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOrientation(
357         LPDIRECTSOUND3DBUFFER iface,
358         LPD3DVECTOR lpvConeOrientation)
359 {
360         ICOM_THIS(IDirectSound3DBufferImpl,iface);
361         TRACE("returning: Cone Orientation vector = (%f,%f,%f)\n", This->ds3db.vConeOrientation.u1.x, This->ds3db.vConeOrientation.u2.y, This->ds3db.vConeOrientation.u3.z);
362         *lpvConeOrientation = This->ds3db.vConeOrientation;
363         return DS_OK;
364 }
365
366 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOutsideVolume(
367         LPDIRECTSOUND3DBUFFER iface,
368         LPLONG lplConeOutsideVolume)
369 {
370         ICOM_THIS(IDirectSound3DBufferImpl,iface);
371         TRACE("returning: Cone Outside Volume = %ld\n", This->ds3db.lConeOutsideVolume);
372         *lplConeOutsideVolume = This->ds3db.lConeOutsideVolume;
373         return DS_OK;
374 }
375
376 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMaxDistance(
377         LPDIRECTSOUND3DBUFFER iface,
378         LPD3DVALUE lpfMaxDistance)
379 {
380         ICOM_THIS(IDirectSound3DBufferImpl,iface);
381         TRACE("returning: Max Distance = %f\n", This->ds3db.flMaxDistance);
382         *lpfMaxDistance = This->ds3db.flMaxDistance;
383         return DS_OK;
384 }
385
386 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMinDistance(
387         LPDIRECTSOUND3DBUFFER iface,
388         LPD3DVALUE lpfMinDistance)
389 {
390         ICOM_THIS(IDirectSound3DBufferImpl,iface);
391         TRACE("returning: Min Distance = %f\n", This->ds3db.flMinDistance);
392         *lpfMinDistance = This->ds3db.flMinDistance;
393         return DS_OK;
394 }
395
396 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMode(
397         LPDIRECTSOUND3DBUFFER iface,
398         LPDWORD lpdwMode)
399 {
400         ICOM_THIS(IDirectSound3DBufferImpl,iface);
401         TRACE("returning: Mode = %ld\n", This->ds3db.dwMode);
402         *lpdwMode = This->ds3db.dwMode;
403         return DS_OK;
404 }
405
406 static HRESULT WINAPI IDirectSound3DBufferImpl_GetPosition(
407         LPDIRECTSOUND3DBUFFER iface,
408         LPD3DVECTOR lpvPosition)
409 {
410         ICOM_THIS(IDirectSound3DBufferImpl,iface);
411         TRACE("returning: Position vector = (%f,%f,%f)\n", This->ds3db.vPosition.u1.x, This->ds3db.vPosition.u2.y, This->ds3db.vPosition.u1.x);
412         *lpvPosition = This->ds3db.vPosition;
413         return DS_OK;
414 }
415
416 static HRESULT WINAPI IDirectSound3DBufferImpl_GetVelocity(
417         LPDIRECTSOUND3DBUFFER iface,
418         LPD3DVECTOR lpvVelocity)
419 {
420         ICOM_THIS(IDirectSound3DBufferImpl,iface);
421         TRACE("returning: Velocity vector = (%f,%f,%f)\n", This->ds3db.vVelocity.u1.x, This->ds3db.vVelocity.u2.y, This->ds3db.vVelocity.u3.z);
422         *lpvVelocity = This->ds3db.vVelocity;
423         return DS_OK;
424 }
425
426 static HRESULT WINAPI IDirectSound3DBufferImpl_SetAllParameters(
427         LPDIRECTSOUND3DBUFFER iface,
428         LPCDS3DBUFFER lpcDs3dBuffer,
429         DWORD dwApply)
430 {
431         ICOM_THIS(IDirectSound3DBufferImpl,iface);
432         TRACE("setting: all parameters; dwApply = %ld\n", dwApply);
433         This->ds3db = *lpcDs3dBuffer;
434         if (dwApply == DS3D_IMMEDIATE)
435         {
436                 DSOUND_Mix3DBuffer(This);
437         }
438         This->need_recalc = TRUE;
439         return DS_OK;
440 }
441
442 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeAngles(
443         LPDIRECTSOUND3DBUFFER iface,
444         DWORD dwInsideConeAngle,
445         DWORD dwOutsideConeAngle,
446         DWORD dwApply)
447 {
448         ICOM_THIS(IDirectSound3DBufferImpl,iface);
449         TRACE("setting: Inside Cone Angle = %ld; Outside Cone Angle = %ld; dwApply = %ld\n", dwInsideConeAngle, dwOutsideConeAngle, dwApply);
450         This->ds3db.dwInsideConeAngle = dwInsideConeAngle;
451         This->ds3db.dwOutsideConeAngle = dwOutsideConeAngle;
452         if (dwApply == DS3D_IMMEDIATE)
453         {
454                 DSOUND_Mix3DBuffer(This);
455         }
456         This->need_recalc = TRUE;
457         return DS_OK;
458 }
459
460 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOrientation(
461         LPDIRECTSOUND3DBUFFER iface,
462         D3DVALUE x, D3DVALUE y, D3DVALUE z,
463         DWORD dwApply)
464 {
465         ICOM_THIS(IDirectSound3DBufferImpl,iface);
466         TRACE("setting: Cone Orientation vector = (%f,%f,%f); dwApply = %ld\n", x, y, z, dwApply);
467         This->ds3db.vConeOrientation.u1.x = x;
468         This->ds3db.vConeOrientation.u2.y = y;
469         This->ds3db.vConeOrientation.u3.z = z;
470         if (dwApply == DS3D_IMMEDIATE)
471         {
472                 This->need_recalc = FALSE;
473                 DSOUND_Mix3DBuffer(This);
474         }
475         This->need_recalc = TRUE;
476         return DS_OK;
477 }
478
479 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOutsideVolume(
480         LPDIRECTSOUND3DBUFFER iface,
481         LONG lConeOutsideVolume,
482         DWORD dwApply)
483 {
484         ICOM_THIS(IDirectSound3DBufferImpl,iface);
485         TRACE("setting: ConeOutsideVolume = %ld; dwApply = %ld\n", lConeOutsideVolume, dwApply);
486         This->ds3db.lConeOutsideVolume = lConeOutsideVolume;
487         if (dwApply == DS3D_IMMEDIATE)
488         {
489                 This->need_recalc = FALSE;
490                 DSOUND_Mix3DBuffer(This);
491         }
492         This->need_recalc = TRUE;
493         return DS_OK;
494 }
495
496 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMaxDistance(
497         LPDIRECTSOUND3DBUFFER iface,
498         D3DVALUE fMaxDistance,
499         DWORD dwApply)
500 {
501         ICOM_THIS(IDirectSound3DBufferImpl,iface);
502         TRACE("setting: MaxDistance = %f; dwApply = %ld\n", fMaxDistance, dwApply);
503         This->ds3db.flMaxDistance = fMaxDistance;
504         if (dwApply == DS3D_IMMEDIATE)
505         {
506                 This->need_recalc = FALSE;
507                 DSOUND_Mix3DBuffer(This);
508         }
509         This->need_recalc = TRUE;
510         return DS_OK;
511 }
512
513 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMinDistance(
514         LPDIRECTSOUND3DBUFFER iface,
515         D3DVALUE fMinDistance,
516         DWORD dwApply)
517 {
518         ICOM_THIS(IDirectSound3DBufferImpl,iface);
519         TRACE("setting: MinDistance = %f; dwApply = %ld\n", fMinDistance, dwApply);
520         This->ds3db.flMinDistance = fMinDistance;
521         if (dwApply == DS3D_IMMEDIATE)
522         {
523                 This->need_recalc = FALSE;
524                 DSOUND_Mix3DBuffer(This);
525         }
526         This->need_recalc = TRUE;
527         return DS_OK;
528 }
529
530 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMode(
531         LPDIRECTSOUND3DBUFFER iface,
532         DWORD dwMode,
533         DWORD dwApply)
534 {
535         ICOM_THIS(IDirectSound3DBufferImpl,iface);
536         TRACE("setting: Mode = %ld; dwApply = %ld\n", dwMode, dwApply);
537         This->ds3db.dwMode = dwMode;
538         if (dwApply == DS3D_IMMEDIATE)
539         {
540                 This->need_recalc = FALSE;
541                 DSOUND_Mix3DBuffer(This);
542         }
543         This->need_recalc = TRUE;
544         return DS_OK;
545 }
546
547 static HRESULT WINAPI IDirectSound3DBufferImpl_SetPosition(
548         LPDIRECTSOUND3DBUFFER iface,
549         D3DVALUE x, D3DVALUE y, D3DVALUE z,
550         DWORD dwApply)
551 {
552         ICOM_THIS(IDirectSound3DBufferImpl,iface);
553         TRACE("setting: Position vector = (%f,%f,%f); dwApply = %ld\n", x, y, z, dwApply);
554         This->ds3db.vPosition.u1.x = x;
555         This->ds3db.vPosition.u2.y = y;
556         This->ds3db.vPosition.u3.z = z;
557         if (dwApply == DS3D_IMMEDIATE)
558         {
559                 This->need_recalc = FALSE;
560                 DSOUND_Mix3DBuffer(This);
561         }
562         This->need_recalc = TRUE;
563         return DS_OK;
564 }
565
566 static HRESULT WINAPI IDirectSound3DBufferImpl_SetVelocity(
567         LPDIRECTSOUND3DBUFFER iface,
568         D3DVALUE x, D3DVALUE y, D3DVALUE z,
569         DWORD dwApply)
570 {
571         ICOM_THIS(IDirectSound3DBufferImpl,iface);
572         TRACE("setting: Velocity vector = (%f,%f,%f); dwApply = %ld\n", x, y, z, dwApply);
573         This->ds3db.vVelocity.u1.x = x;
574         This->ds3db.vVelocity.u2.y = y;
575         This->ds3db.vVelocity.u3.z = z;
576         if (dwApply == DS3D_IMMEDIATE)
577         {
578                 This->need_recalc = FALSE;
579                 DSOUND_Mix3DBuffer(This);
580         }
581         This->need_recalc = TRUE;
582         return DS_OK;
583 }
584
585 static ICOM_VTABLE(IDirectSound3DBuffer) ds3dbvt =
586 {
587         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
588         /* IUnknown methods */
589         IDirectSound3DBufferImpl_QueryInterface,
590         IDirectSound3DBufferImpl_AddRef,
591         IDirectSound3DBufferImpl_Release,
592         /* IDirectSound3DBuffer methods */
593         IDirectSound3DBufferImpl_GetAllParameters,
594         IDirectSound3DBufferImpl_GetConeAngles,
595         IDirectSound3DBufferImpl_GetConeOrientation,
596         IDirectSound3DBufferImpl_GetConeOutsideVolume,
597         IDirectSound3DBufferImpl_GetMaxDistance,
598         IDirectSound3DBufferImpl_GetMinDistance,
599         IDirectSound3DBufferImpl_GetMode,
600         IDirectSound3DBufferImpl_GetPosition,
601         IDirectSound3DBufferImpl_GetVelocity,
602         IDirectSound3DBufferImpl_SetAllParameters,
603         IDirectSound3DBufferImpl_SetConeAngles,
604         IDirectSound3DBufferImpl_SetConeOrientation,
605         IDirectSound3DBufferImpl_SetConeOutsideVolume,
606         IDirectSound3DBufferImpl_SetMaxDistance,
607         IDirectSound3DBufferImpl_SetMinDistance,
608         IDirectSound3DBufferImpl_SetMode,
609         IDirectSound3DBufferImpl_SetPosition,
610         IDirectSound3DBufferImpl_SetVelocity,
611 };
612
613 HRESULT WINAPI IDirectSound3DBufferImpl_Create(
614         IDirectSoundBufferImpl *This,
615         IDirectSound3DBufferImpl **pds3db)
616 {
617         IDirectSound3DBufferImpl *ds3db;
618
619         ds3db = (IDirectSound3DBufferImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(*ds3db));
620         ds3db->ref = 0;
621         ds3db->dsb = This;
622         ICOM_VTBL(ds3db) = &ds3dbvt;
623         InitializeCriticalSection(&ds3db->lock);
624
625         ds3db->ds3db.dwSize = sizeof(DS3DBUFFER);
626         ds3db->ds3db.vPosition.u1.x = 0.0;
627         ds3db->ds3db.vPosition.u2.y = 0.0;
628         ds3db->ds3db.vPosition.u3.z = 0.0;
629         ds3db->ds3db.vVelocity.u1.x = 0.0;
630         ds3db->ds3db.vVelocity.u2.y = 0.0;
631         ds3db->ds3db.vVelocity.u3.z = 0.0;
632         ds3db->ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
633         ds3db->ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
634         ds3db->ds3db.vConeOrientation.u1.x = 0.0;
635         ds3db->ds3db.vConeOrientation.u2.y = 0.0;
636         ds3db->ds3db.vConeOrientation.u3.z = 0.0;
637         ds3db->ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
638         ds3db->ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
639         ds3db->ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
640         ds3db->ds3db.dwMode = DS3DMODE_NORMAL;
641
642         *pds3db = ds3db;
643         return S_OK;
644 }
645
646 /*******************************************************************************
647  *            IDirectSound3DListener
648  */
649
650 /* IUnknown methods */
651 static HRESULT WINAPI IDirectSound3DListenerImpl_QueryInterface(
652         LPDIRECTSOUND3DLISTENER iface, REFIID riid, LPVOID *ppobj)
653 {
654         ICOM_THIS(IDirectSound3DListenerImpl,iface);
655
656         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
657         return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb, riid, ppobj);
658 }
659
660 static ULONG WINAPI IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface)
661 {
662         ICOM_THIS(IDirectSound3DListenerImpl,iface);
663         return InterlockedIncrement(&This->ref);
664 }
665
666 static ULONG WINAPI IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface)
667 {
668         ICOM_THIS(IDirectSound3DListenerImpl,iface);
669         ULONG ulReturn;
670
671         TRACE("(%p) ref was %ld\n", This, This->ref);
672
673         ulReturn = InterlockedDecrement(&This->ref);
674
675         /* Free all resources */
676         if( ulReturn == 0 ) {
677                 if(This->dsb)
678                         IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
679                 DeleteCriticalSection(&This->lock);
680                 HeapFree(GetProcessHeap(),0,This);
681         }
682
683         return ulReturn;
684 }
685
686 /* IDirectSound3DListener methods */
687 static HRESULT WINAPI IDirectSound3DListenerImpl_GetAllParameter(
688         LPDIRECTSOUND3DLISTENER iface,
689         LPDS3DLISTENER lpDS3DL)
690 {
691         ICOM_THIS(IDirectSound3DListenerImpl,iface);
692         TRACE("returning: all parameters\n");
693         *lpDS3DL = This->ds3dl;
694         return DS_OK;
695 }
696
697 static HRESULT WINAPI IDirectSound3DListenerImpl_GetDistanceFactor(
698         LPDIRECTSOUND3DLISTENER iface,
699         LPD3DVALUE lpfDistanceFactor)
700 {
701         ICOM_THIS(IDirectSound3DListenerImpl,iface);
702         TRACE("returning: Distance Factor = %f\n", This->ds3dl.flDistanceFactor);
703         *lpfDistanceFactor = This->ds3dl.flDistanceFactor;
704         return DS_OK;
705 }
706
707 static HRESULT WINAPI IDirectSound3DListenerImpl_GetDopplerFactor(
708         LPDIRECTSOUND3DLISTENER iface,
709         LPD3DVALUE lpfDopplerFactor)
710 {
711         ICOM_THIS(IDirectSound3DListenerImpl,iface);
712         TRACE("returning: Doppler Factor = %f\n", This->ds3dl.flDopplerFactor);
713         *lpfDopplerFactor = This->ds3dl.flDopplerFactor;
714         return DS_OK;
715 }
716
717 static HRESULT WINAPI IDirectSound3DListenerImpl_GetOrientation(
718         LPDIRECTSOUND3DLISTENER iface,
719         LPD3DVECTOR lpvOrientFront,
720         LPD3DVECTOR lpvOrientTop)
721 {
722         ICOM_THIS(IDirectSound3DListenerImpl,iface);
723         TRACE("returning: OrientFront vector = (%f,%f,%f); OrientTop vector = (%f,%f,%f)\n", This->ds3dl.vOrientFront.u1.x, \
724         This->ds3dl.vOrientFront.u2.y, This->ds3dl.vOrientFront.u3.z, This->ds3dl.vOrientTop.u1.x, This->ds3dl.vOrientTop.u2.y, \
725         This->ds3dl.vOrientTop.u3.z);
726         *lpvOrientFront = This->ds3dl.vOrientFront;
727         *lpvOrientTop = This->ds3dl.vOrientTop;
728         return DS_OK;
729 }
730
731 static HRESULT WINAPI IDirectSound3DListenerImpl_GetPosition(
732         LPDIRECTSOUND3DLISTENER iface,
733         LPD3DVECTOR lpvPosition)
734 {
735         ICOM_THIS(IDirectSound3DListenerImpl,iface);
736         TRACE("returning: Position vector = (%f,%f,%f)\n", This->ds3dl.vPosition.u1.x, This->ds3dl.vPosition.u2.y, This->ds3dl.vPosition.u3.z);
737         *lpvPosition = This->ds3dl.vPosition;
738         return DS_OK;
739 }
740
741 static HRESULT WINAPI IDirectSound3DListenerImpl_GetRolloffFactor(
742         LPDIRECTSOUND3DLISTENER iface,
743         LPD3DVALUE lpfRolloffFactor)
744 {
745         ICOM_THIS(IDirectSound3DListenerImpl,iface);
746         TRACE("returning: RolloffFactor = %f\n", This->ds3dl.flRolloffFactor);
747         *lpfRolloffFactor = This->ds3dl.flRolloffFactor;
748         return DS_OK;
749 }
750
751 static HRESULT WINAPI IDirectSound3DListenerImpl_GetVelocity(
752         LPDIRECTSOUND3DLISTENER iface,
753         LPD3DVECTOR lpvVelocity)
754 {
755         ICOM_THIS(IDirectSound3DListenerImpl,iface);
756         TRACE("returning: Velocity vector = (%f,%f,%f)\n", This->ds3dl.vVelocity.u1.x, This->ds3dl.vVelocity.u2.y, This->ds3dl.vVelocity.u3.z);
757         *lpvVelocity = This->ds3dl.vVelocity;
758         return DS_OK;
759 }
760
761 static HRESULT WINAPI IDirectSound3DListenerImpl_SetAllParameters(
762         LPDIRECTSOUND3DLISTENER iface,
763         LPCDS3DLISTENER lpcDS3DL,
764         DWORD dwApply)
765 {
766         ICOM_THIS(IDirectSound3DListenerImpl,iface);
767         TRACE("setting: all parameters; dwApply = %ld\n", dwApply);
768         This->ds3dl = *lpcDS3DL;
769         if (dwApply == DS3D_IMMEDIATE)
770         {
771                 This->need_recalc = FALSE;
772                 DSOUND_ChangeListener(This);
773         }
774         This->need_recalc = TRUE;
775         return DS_OK;
776 }
777
778 static HRESULT WINAPI IDirectSound3DListenerImpl_SetDistanceFactor(
779         LPDIRECTSOUND3DLISTENER iface,
780         D3DVALUE fDistanceFactor,
781         DWORD dwApply)
782 {
783         ICOM_THIS(IDirectSound3DListenerImpl,iface);
784         TRACE("setting: Distance Factor = %f; dwApply = %ld\n", fDistanceFactor, dwApply);
785         This->ds3dl.flDistanceFactor = fDistanceFactor;
786         if (dwApply == DS3D_IMMEDIATE)
787         {
788                 This->need_recalc = FALSE;
789                 DSOUND_ChangeListener(This);
790         }
791         This->need_recalc = TRUE;
792         return DS_OK;
793 }
794
795 static HRESULT WINAPI IDirectSound3DListenerImpl_SetDopplerFactor(
796         LPDIRECTSOUND3DLISTENER iface,
797         D3DVALUE fDopplerFactor,
798         DWORD dwApply)
799 {
800         ICOM_THIS(IDirectSound3DListenerImpl,iface);
801         TRACE("setting: Doppler Factor = %f; dwApply = %ld\n", fDopplerFactor, dwApply);
802         This->ds3dl.flDopplerFactor = fDopplerFactor;
803         if (dwApply == DS3D_IMMEDIATE)
804         {
805                 This->need_recalc = FALSE;
806                 DSOUND_ChangeListener(This);
807         }
808         This->need_recalc = TRUE;
809         return DS_OK;
810 }
811
812 static HRESULT WINAPI IDirectSound3DListenerImpl_SetOrientation(
813         LPDIRECTSOUND3DLISTENER iface,
814         D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront,
815         D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop,
816         DWORD dwApply)
817 {
818         ICOM_THIS(IDirectSound3DListenerImpl,iface);
819         TRACE("setting: Front vector = (%f,%f,%f); Top vector = (%f,%f,%f); dwApply = %ld\n", \
820         xFront, yFront, zFront, xTop, yTop, zTop, dwApply);
821         This->ds3dl.vOrientFront.u1.x = xFront;
822         This->ds3dl.vOrientFront.u2.y = yFront;
823         This->ds3dl.vOrientFront.u3.z = zFront;
824         This->ds3dl.vOrientTop.u1.x = xTop;
825         This->ds3dl.vOrientTop.u2.y = yTop;
826         This->ds3dl.vOrientTop.u3.z = zTop;
827         if (dwApply == DS3D_IMMEDIATE)
828         {
829                 This->need_recalc = FALSE;
830                 DSOUND_ChangeListener(This);
831         }
832         This->need_recalc = TRUE;
833         return DS_OK;
834 }
835
836 static HRESULT WINAPI IDirectSound3DListenerImpl_SetPosition(
837         LPDIRECTSOUND3DLISTENER iface,
838         D3DVALUE x, D3DVALUE y, D3DVALUE z,
839         DWORD dwApply)
840 {
841         ICOM_THIS(IDirectSound3DListenerImpl,iface);
842         TRACE("setting: Position vector = (%f,%f,%f); dwApply = %ld\n", x, y, z, dwApply);
843         This->ds3dl.vPosition.u1.x = x;
844         This->ds3dl.vPosition.u2.y = y;
845         This->ds3dl.vPosition.u3.z = z;
846         if (dwApply == DS3D_IMMEDIATE)
847         {
848                 This->need_recalc = FALSE;
849                 DSOUND_ChangeListener(This);
850         }
851         This->need_recalc = TRUE;
852         return DS_OK;
853 }
854
855 static HRESULT WINAPI IDirectSound3DListenerImpl_SetRolloffFactor(
856         LPDIRECTSOUND3DLISTENER iface,
857         D3DVALUE fRolloffFactor,
858         DWORD dwApply)
859 {
860         ICOM_THIS(IDirectSound3DListenerImpl,iface);
861         TRACE("setting: Rolloff Factor = %f; dwApply = %ld\n", fRolloffFactor, dwApply);
862         This->ds3dl.flRolloffFactor = fRolloffFactor;
863         if (dwApply == DS3D_IMMEDIATE)
864         {
865                 This->need_recalc = FALSE;
866                 DSOUND_ChangeListener(This);
867         }
868         This->need_recalc = TRUE;
869         return DS_OK;
870 }
871
872 static HRESULT WINAPI IDirectSound3DListenerImpl_SetVelocity(
873         LPDIRECTSOUND3DLISTENER iface,
874         D3DVALUE x, D3DVALUE y, D3DVALUE z,
875         DWORD dwApply)
876 {
877         ICOM_THIS(IDirectSound3DListenerImpl,iface);
878         TRACE("setting: Velocity vector = (%f,%f,%f); dwApply = %ld\n", x, y, z, dwApply);
879         This->ds3dl.vVelocity.u1.x = x;
880         This->ds3dl.vVelocity.u2.y = y;
881         This->ds3dl.vVelocity.u3.z = z;
882         if (dwApply == DS3D_IMMEDIATE)
883         {
884                 This->need_recalc = FALSE;
885                 DSOUND_ChangeListener(This);
886         }
887         This->need_recalc = TRUE;
888         return DS_OK;
889 }
890
891 static HRESULT WINAPI IDirectSound3DListenerImpl_CommitDeferredSettings(
892         LPDIRECTSOUND3DLISTENER iface)
893
894 {
895         ICOM_THIS(IDirectSound3DListenerImpl,iface);
896         TRACE("\n");
897         DSOUND_ChangeListener(This);
898         return DS_OK;
899 }
900
901 static ICOM_VTABLE(IDirectSound3DListener) ds3dlvt =
902 {
903         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
904         /* IUnknown methods */
905         IDirectSound3DListenerImpl_QueryInterface,
906         IDirectSound3DListenerImpl_AddRef,
907         IDirectSound3DListenerImpl_Release,
908         /* IDirectSound3DListener methods */
909         IDirectSound3DListenerImpl_GetAllParameter,
910         IDirectSound3DListenerImpl_GetDistanceFactor,
911         IDirectSound3DListenerImpl_GetDopplerFactor,
912         IDirectSound3DListenerImpl_GetOrientation,
913         IDirectSound3DListenerImpl_GetPosition,
914         IDirectSound3DListenerImpl_GetRolloffFactor,
915         IDirectSound3DListenerImpl_GetVelocity,
916         IDirectSound3DListenerImpl_SetAllParameters,
917         IDirectSound3DListenerImpl_SetDistanceFactor,
918         IDirectSound3DListenerImpl_SetDopplerFactor,
919         IDirectSound3DListenerImpl_SetOrientation,
920         IDirectSound3DListenerImpl_SetPosition,
921         IDirectSound3DListenerImpl_SetRolloffFactor,
922         IDirectSound3DListenerImpl_SetVelocity,
923         IDirectSound3DListenerImpl_CommitDeferredSettings,
924 };
925
926 HRESULT WINAPI IDirectSound3DListenerImpl_Create(
927         PrimaryBufferImpl *This,
928         IDirectSound3DListenerImpl **pdsl)
929 {
930         IDirectSound3DListenerImpl *dsl;
931
932         dsl = (IDirectSound3DListenerImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsl));
933         dsl->ref = 1;
934         ICOM_VTBL(dsl) = &ds3dlvt;
935
936         dsl->ds3dl.dwSize = sizeof(DS3DLISTENER);
937         dsl->ds3dl.vPosition.u1.x = 0.0;
938         dsl->ds3dl.vPosition.u2.y = 0.0;
939         dsl->ds3dl.vPosition.u3.z = 0.0;
940         dsl->ds3dl.vVelocity.u1.x = 0.0;
941         dsl->ds3dl.vVelocity.u2.y = 0.0;
942         dsl->ds3dl.vVelocity.u3.z = 0.0;
943         dsl->ds3dl.vOrientFront.u1.x = 0.0;
944         dsl->ds3dl.vOrientFront.u2.y = 0.0;
945         dsl->ds3dl.vOrientFront.u3.z = 1.0;
946         dsl->ds3dl.vOrientTop.u1.x = 0.0;
947         dsl->ds3dl.vOrientTop.u2.y = 1.0;
948         dsl->ds3dl.vOrientTop.u3.z = 0.0;
949         dsl->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
950         dsl->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
951         dsl->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
952
953         InitializeCriticalSection(&dsl->lock);
954
955         dsl->dsb = This;
956         IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This);
957
958         *pdsl = dsl;
959         return S_OK;
960 }