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