Fixed some issues found by winapi_check.
[wine] / dlls / dsound / dsound_main.c
1 /*                      DirectSound
2  * 
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998 Rob Riggs
5  * Copyright 2000 Ove Kåven, TransGaming Technologies, Inc.
6  */
7 /*
8  * Most thread locking is complete. There may be a few race
9  * conditions still lurking.
10  *
11  * Tested with a Soundblaster clone, a Gravis UltraSound Classic,
12  * and a Turtle Beach Tropez+.
13  *
14  * TODO:
15  *      Implement DirectSoundCapture API
16  *      Implement SetCooperativeLevel properly (need to address focus issues)
17  *      Implement DirectSound3DBuffers (stubs in place)
18  *      Use hardware 3D support if available
19  *      Add critical section locking inside Release and AddRef methods
20  *      Handle static buffers - put those in hardware, non-static not in hardware
21  *      Hardware DuplicateSoundBuffer
22  *      Proper volume calculation, and setting volume in HEL primary buffer
23  *      Optimize WINMM and negotiate fragment size, decrease DS_HEL_MARGIN
24  */
25
26 #include "config.h"
27 #include <assert.h>
28 #include <stdio.h>
29 #include <sys/types.h>
30 #include <sys/fcntl.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <math.h>       /* Insomnia - pow() function */
35
36 #include "windef.h"
37 #include "wingdi.h"
38 #include "winuser.h"
39 #include "winerror.h"
40 #include "mmsystem.h"
41 #include "wine/windef16.h"
42 #include "debugtools.h"
43 #include "dsound.h"
44 #include "dsdriver.h"
45
46 DEFAULT_DEBUG_CHANNEL(dsound);
47
48 /* these are eligible for tuning... they must be high on slow machines... */
49 /* especially since the WINMM overhead is pretty high, and could be improved quite a bit;
50  * the high DS_HEL_MARGIN reflects the currently high wineoss/HEL latency
51  * some settings here should probably get ported to wine.conf */
52 #define DS_EMULDRIVER 1 /* some games (Quake 2, UT) refuse to accept
53                                 emulated dsound devices. set to 0 ! */ 
54 #define DS_HEL_FRAGS 48 /* HEL only: number of waveOut fragments in primary buffer */
55 #define DS_HEL_QUEUE 28 /* HEL only: number of waveOut fragments to prebuffer */
56                         /* (Starcraft videos won't work with higher than 32 x10ms) */
57 #define DS_HEL_MARGIN 4 /* HEL only: number of waveOut fragments ahead to mix in new buffers */
58
59 #define DS_HAL_QUEUE 28 /* HAL only: max number of fragments to prebuffer */
60
61 /* Linux does not support better timing than 10ms */
62 #define DS_TIME_RES 10  /* Resolution of multimedia timer */
63 #define DS_TIME_DEL 10  /* Delay of multimedia timer callback, and duration of HEL fragment */
64
65 /*****************************************************************************
66  * Predeclare the interface implementation structures
67  */
68 typedef struct IDirectSoundImpl IDirectSoundImpl;
69 typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl;
70 typedef struct IDirectSoundNotifyImpl IDirectSoundNotifyImpl;
71 typedef struct IDirectSound3DListenerImpl IDirectSound3DListenerImpl;
72 typedef struct IDirectSound3DBufferImpl IDirectSound3DBufferImpl;
73 typedef struct IDirectSoundCaptureImpl IDirectSoundCaptureImpl;
74 typedef struct IDirectSoundCaptureBufferImpl IDirectSoundCaptureBufferImpl;
75
76 /*****************************************************************************
77  * IDirectSound implementation structure
78  */
79 struct IDirectSoundImpl
80 {
81     /* IUnknown fields */
82     ICOM_VFIELD(IDirectSound);
83     DWORD                      ref;
84     /* IDirectSoundImpl fields */
85     PIDSDRIVER                  driver;
86     DSDRIVERDESC                drvdesc;
87     DSDRIVERCAPS                drvcaps;
88     HWAVEOUT                    hwo;
89     LPWAVEHDR                   pwave[DS_HEL_FRAGS];
90     UINT                        timerID, pwplay, pwwrite, pwqueue;
91     DWORD                       fraglen;
92     DWORD                       priolevel;
93     int                         nrofbuffers;
94     IDirectSoundBufferImpl**    buffers;
95     IDirectSoundBufferImpl*     primary;
96     IDirectSound3DListenerImpl* listener;
97     WAVEFORMATEX                wfx; /* current main waveformat */
98     CRITICAL_SECTION            lock;
99 };
100
101 /*****************************************************************************
102  * IDirectSoundBuffer implementation structure
103  */
104 struct IDirectSoundBufferImpl
105 {
106     /* IUnknown fields */
107     ICOM_VFIELD(IDirectSoundBuffer);
108     DWORD                            ref;
109     /* IDirectSoundBufferImpl fields */
110     PIDSDRIVERBUFFER          hwbuf;
111     WAVEFORMATEX              wfx;
112     LPBYTE                    buffer;
113     IDirectSound3DBufferImpl* ds3db;
114     DWORD                     playflags,state,leadin;
115     DWORD                     playpos,mixpos,startpos,writelead,buflen;
116     DWORD                     nAvgBytesPerSec;
117     DWORD                     freq;
118     ULONG                     freqAdjust;
119     DSVOLUMEPAN               volpan;
120     IDirectSoundBufferImpl*   parent;         /* for duplicates */
121     IDirectSoundImpl*         dsound;
122     DSBUFFERDESC              dsbd;
123     LPDSBPOSITIONNOTIFY       notifies;
124     int                       nrofnotifies;
125     CRITICAL_SECTION          lock;
126 };
127
128 #define STATE_STOPPED  0
129 #define STATE_STARTING 1
130 #define STATE_PLAYING  2
131 #define STATE_STOPPING 3
132
133 /*****************************************************************************
134  * IDirectSoundNotify implementation structure
135  */
136 struct IDirectSoundNotifyImpl
137 {
138     /* IUnknown fields */
139     ICOM_VFIELD(IDirectSoundNotify);
140     DWORD                            ref;
141     /* IDirectSoundNotifyImpl fields */
142     IDirectSoundBufferImpl* dsb;
143 };
144
145 /*****************************************************************************
146  *  IDirectSound3DListener implementation structure
147  */
148 struct IDirectSound3DListenerImpl
149 {
150     /* IUnknown fields */
151     ICOM_VFIELD(IDirectSound3DListener);
152     DWORD                                ref;
153     /* IDirectSound3DListenerImpl fields */
154     IDirectSoundBufferImpl* dsb;
155     DS3DLISTENER            ds3dl;
156     CRITICAL_SECTION        lock;   
157 };
158
159 /*****************************************************************************
160  * IDirectSound3DBuffer implementation structure
161  */
162 struct IDirectSound3DBufferImpl
163 {
164     /* IUnknown fields */
165     ICOM_VFIELD(IDirectSound3DBuffer);
166     DWORD                              ref;
167     /* IDirectSound3DBufferImpl fields */
168     IDirectSoundBufferImpl* dsb;
169     DS3DBUFFER              ds3db;
170     LPBYTE                  buffer;
171     DWORD                   buflen;
172     CRITICAL_SECTION        lock;
173 };
174
175
176 /*****************************************************************************
177  * IDirectSoundCapture implementation structure
178  */
179 struct IDirectSoundCaptureImpl
180 {
181     /* IUnknown fields */
182     ICOM_VFIELD(IDirectSoundCapture);
183     DWORD                              ref;
184
185     /* IDirectSoundCaptureImpl fields */
186     CRITICAL_SECTION        lock;
187 };
188
189 /*****************************************************************************
190  * IDirectSoundCapture implementation structure
191  */
192 struct IDirectSoundCaptureBufferImpl
193 {
194     /* IUnknown fields */
195     ICOM_VFIELD(IDirectSoundCaptureBuffer);
196     DWORD                              ref;
197
198     /* IDirectSoundCaptureBufferImpl fields */
199     CRITICAL_SECTION        lock;
200 };
201
202
203 /* #define USE_DSOUND3D 1 */
204
205 #define DSOUND_FREQSHIFT (14)
206
207 static IDirectSoundImpl*        dsound = NULL;
208
209 static IDirectSoundBufferImpl*  primarybuf = NULL;
210
211 static void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len);
212
213 static HRESULT DSOUND_CreateDirectSoundCapture( LPVOID* ppobj );
214 static HRESULT DSOUND_CreateDirectSoundCaptureBuffer( LPCDSCBUFFERDESC lpcDSCBufferDesc, LPVOID* ppobj );
215
216 static ICOM_VTABLE(IDirectSoundCapture) dscvt;
217 static ICOM_VTABLE(IDirectSoundCaptureBuffer) dscbvt;
218
219 static HRESULT mmErr(UINT err)
220 {
221         switch(err) {
222         case MMSYSERR_NOERROR:
223                 return DS_OK;
224         case MMSYSERR_ALLOCATED:
225                 return DSERR_ALLOCATED;
226         case MMSYSERR_INVALHANDLE:
227                 return DSERR_GENERIC; /* FIXME */
228         case MMSYSERR_NODRIVER:
229                 return DSERR_NODRIVER;
230         case MMSYSERR_NOMEM:
231                 return DSERR_OUTOFMEMORY;
232         case MMSYSERR_INVALPARAM:
233                 return DSERR_INVALIDPARAM;
234         default:
235                 FIXME("Unknown MMSYS error %d\n",err);
236                 return DSERR_GENERIC;
237         }
238 }
239
240 /***************************************************************************
241  * DirectSoundEnumerateA [DSOUND.2]  
242  *
243  * Enumerate all DirectSound drivers installed in the system
244  *
245  * RETURNS
246  *    Success: DS_OK
247  *    Failure: DSERR_INVALIDPARAM
248  */
249 HRESULT WINAPI DirectSoundEnumerateA(
250         LPDSENUMCALLBACKA lpDSEnumCallback,
251         LPVOID lpContext)
252 {
253         TRACE("lpDSEnumCallback = %p, lpContext = %p\n", 
254                 lpDSEnumCallback, lpContext);
255
256 #ifdef HAVE_OSS
257         if (lpDSEnumCallback != NULL)
258                 lpDSEnumCallback(NULL,"WINE DirectSound using Open Sound System",
259                     "sound",lpContext);
260 #endif
261
262         return DS_OK;
263 }
264
265 /***************************************************************************
266  * DirectSoundEnumerateW [DSOUND.3]  
267  *
268  * Enumerate all DirectSound drivers installed in the system
269  *
270  * RETURNS
271  *    Success: DS_OK
272  *    Failure: DSERR_INVALIDPARAM
273  */
274 HRESULT WINAPI DirectSoundEnumerateW(
275         LPDSENUMCALLBACKW lpDSEnumCallback, 
276         LPVOID lpContext )
277 {
278         FIXME("lpDSEnumCallback = %p, lpContext = %p: stub\n", 
279                 lpDSEnumCallback, lpContext);
280
281         return DS_OK;
282 }
283
284
285 static void _dump_DSBCAPS(DWORD xmask) {
286         struct {
287                 DWORD   mask;
288                 char    *name;
289         } flags[] = {
290 #define FE(x) { x, #x },
291                 FE(DSBCAPS_PRIMARYBUFFER)
292                 FE(DSBCAPS_STATIC)
293                 FE(DSBCAPS_LOCHARDWARE)
294                 FE(DSBCAPS_LOCSOFTWARE)
295                 FE(DSBCAPS_CTRL3D)
296                 FE(DSBCAPS_CTRLFREQUENCY)
297                 FE(DSBCAPS_CTRLPAN)
298                 FE(DSBCAPS_CTRLVOLUME)
299                 FE(DSBCAPS_CTRLPOSITIONNOTIFY)
300                 FE(DSBCAPS_CTRLDEFAULT)
301                 FE(DSBCAPS_CTRLALL)
302                 FE(DSBCAPS_STICKYFOCUS)
303                 FE(DSBCAPS_GLOBALFOCUS)
304                 FE(DSBCAPS_GETCURRENTPOSITION2)
305                 FE(DSBCAPS_MUTE3DATMAXDISTANCE)
306 #undef FE
307         };
308         int     i;
309
310         for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
311                 if ((flags[i].mask & xmask) == flags[i].mask)
312                         DPRINTF("%s ",flags[i].name);
313 }
314
315 /*******************************************************************************
316  *              IDirectSound3DBuffer
317  */
318
319 /* IUnknown methods */
320 #ifdef USE_DSOUND3D
321 static HRESULT WINAPI IDirectSound3DBufferImpl_QueryInterface(
322         LPDIRECTSOUND3DBUFFER iface, REFIID riid, LPVOID *ppobj)
323 {
324         ICOM_THIS(IDirectSound3DBufferImpl,iface);
325
326         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
327         return E_FAIL;
328 }
329 #endif
330
331 #ifdef USE_DSOUND3D
332 static ULONG WINAPI IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface)
333 {
334         ICOM_THIS(IDirectSound3DBufferImpl,iface);
335         This->ref++;
336         return This->ref;
337 }
338 #endif
339
340 #ifdef USE_DSOUND3D
341 static ULONG WINAPI IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface)
342 {
343         ICOM_THIS(IDirectSound3DBufferImpl,iface);
344
345         TRACE("(%p) ref was %ld\n", This, This->ref);
346
347         if(--This->ref)
348                 return This->ref;
349
350         if (This->dsb)
351                 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
352
353         DeleteCriticalSection(&This->lock);
354
355         HeapFree(GetProcessHeap(),0,This->buffer);
356         HeapFree(GetProcessHeap(),0,This);
357
358         return 0;
359 }
360 #endif
361
362 /* IDirectSound3DBuffer methods */
363 #ifdef USE_DSOUND3D
364 static HRESULT WINAPI IDirectSound3DBufferImpl_GetAllParameters(
365         LPDIRECTSOUND3DBUFFER iface,
366         LPDS3DBUFFER lpDs3dBuffer)
367 {
368         FIXME("stub\n");
369         return DS_OK;
370 }
371 #endif
372
373 #ifdef USE_DSOUND3D
374 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeAngles(
375         LPDIRECTSOUND3DBUFFER iface,
376         LPDWORD lpdwInsideConeAngle,
377         LPDWORD lpdwOutsideConeAngle)
378 {
379         FIXME("stub\n");
380         return DS_OK;
381 }
382 #endif
383
384 #ifdef USE_DSOUND3D
385 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOrientation(
386         LPDIRECTSOUND3DBUFFER iface,
387         LPD3DVECTOR lpvConeOrientation)
388 {
389         FIXME("stub\n");
390         return DS_OK;
391 }
392 #endif
393
394 #ifdef USE_DSOUND3D
395 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOutsideVolume(
396         LPDIRECTSOUND3DBUFFER iface,
397         LPLONG lplConeOutsideVolume)
398 {
399         FIXME("stub\n");
400         return DS_OK;
401 }
402 #endif
403
404 #ifdef USE_DSOUND3D
405 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMaxDistance(
406         LPDIRECTSOUND3DBUFFER iface,
407         LPD3DVALUE lpfMaxDistance)
408 {
409         FIXME("stub\n");
410         return DS_OK;
411 }
412 #endif
413
414 #ifdef USE_DSOUND3D
415 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMinDistance(
416         LPDIRECTSOUND3DBUFFER iface,
417         LPD3DVALUE lpfMinDistance)
418 {
419         FIXME("stub\n");
420         return DS_OK;
421 }
422 #endif
423
424 #ifdef USE_DSOUND3D
425 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMode(
426         LPDIRECTSOUND3DBUFFER iface,
427         LPDWORD lpdwMode)
428 {
429         FIXME("stub\n");
430         return DS_OK;
431 }
432 #endif
433
434 #ifdef USE_DSOUND3D
435 static HRESULT WINAPI IDirectSound3DBufferImpl_GetPosition(
436         LPDIRECTSOUND3DBUFFER iface,
437         LPD3DVECTOR lpvPosition)
438 {
439         FIXME("stub\n");
440         return DS_OK;
441 }
442 #endif
443
444 #ifdef USE_DSOUND3D
445 static HRESULT WINAPI IDirectSound3DBufferImpl_GetVelocity(
446         LPDIRECTSOUND3DBUFFER iface,
447         LPD3DVECTOR lpvVelocity)
448 {
449         FIXME("stub\n");
450         return DS_OK;
451 }
452 #endif
453
454 #ifdef USE_DSOUND3D
455 static HRESULT WINAPI IDirectSound3DBufferImpl_SetAllParameters(
456         LPDIRECTSOUND3DBUFFER iface,
457         LPCDS3DBUFFER lpcDs3dBuffer,
458         DWORD dwApply)
459 {
460         FIXME("stub\n");
461         return DS_OK;
462 }
463 #endif
464
465 #ifdef USE_DSOUND3D
466 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeAngles(
467         LPDIRECTSOUND3DBUFFER iface,
468         DWORD dwInsideConeAngle,
469         DWORD dwOutsideConeAngle,
470         DWORD dwApply)
471 {
472         FIXME("stub\n");
473         return DS_OK;
474 }
475 #endif
476
477 #ifdef USE_DSOUND3D
478 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOrientation(
479         LPDIRECTSOUND3DBUFFER iface,
480         D3DVALUE x, D3DVALUE y, D3DVALUE z,
481         DWORD dwApply)
482 {
483         FIXME("stub\n");
484         return DS_OK;
485 }
486 #endif
487
488 #ifdef USE_DSOUND3D
489 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOutsideVolume(
490         LPDIRECTSOUND3DBUFFER iface,
491         LONG lConeOutsideVolume,
492         DWORD dwApply)
493 {
494         FIXME("stub\n");
495         return DS_OK;
496 }
497 #endif
498
499 #ifdef USE_DSOUND3D
500 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMaxDistance(
501         LPDIRECTSOUND3DBUFFER iface,
502         D3DVALUE fMaxDistance,
503         DWORD dwApply)
504 {
505         FIXME("stub\n");
506         return DS_OK;
507 }
508 #endif
509
510 #ifdef USE_DSOUND3D
511 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMinDistance(
512         LPDIRECTSOUND3DBUFFER iface,
513         D3DVALUE fMinDistance,
514         DWORD dwApply)
515 {
516         FIXME("stub\n");
517         return DS_OK;
518 }
519 #endif
520
521 #ifdef USE_DSOUND3D
522 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMode(
523         LPDIRECTSOUND3DBUFFER iface,
524         DWORD dwMode,
525         DWORD dwApply)
526 {
527         ICOM_THIS(IDirectSound3DBufferImpl,iface);
528         TRACE("mode = %lx\n", dwMode);
529         This->ds3db.dwMode = dwMode;
530         return DS_OK;
531 }
532 #endif
533
534 #ifdef USE_DSOUND3D
535 static HRESULT WINAPI IDirectSound3DBufferImpl_SetPosition(
536         LPDIRECTSOUND3DBUFFER iface,
537         D3DVALUE x, D3DVALUE y, D3DVALUE z,
538         DWORD dwApply)
539 {
540         FIXME("stub\n");
541         return DS_OK;
542 }
543 #endif
544
545 #ifdef USE_DSOUND3D
546 static HRESULT WINAPI IDirectSound3DBufferImpl_SetVelocity(
547         LPDIRECTSOUND3DBUFFER iface,
548         D3DVALUE x, D3DVALUE y, D3DVALUE z,
549         DWORD dwApply)
550 {
551         FIXME("stub\n");
552         return DS_OK;
553 }
554 #endif
555
556 #ifdef USE_DSOUND3D
557 static ICOM_VTABLE(IDirectSound3DBuffer) ds3dbvt = 
558 {
559         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
560         /* IUnknown methods */
561         IDirectSound3DBufferImpl_QueryInterface,
562         IDirectSound3DBufferImpl_AddRef,
563         IDirectSound3DBufferImpl_Release,
564         /* IDirectSound3DBuffer methods */
565         IDirectSound3DBufferImpl_GetAllParameters,
566         IDirectSound3DBufferImpl_GetConeAngles,
567         IDirectSound3DBufferImpl_GetConeOrientation,
568         IDirectSound3DBufferImpl_GetConeOutsideVolume,
569         IDirectSound3DBufferImpl_GetMaxDistance,
570         IDirectSound3DBufferImpl_GetMinDistance,
571         IDirectSound3DBufferImpl_GetMode,
572         IDirectSound3DBufferImpl_GetPosition,
573         IDirectSound3DBufferImpl_GetVelocity,
574         IDirectSound3DBufferImpl_SetAllParameters,
575         IDirectSound3DBufferImpl_SetConeAngles,
576         IDirectSound3DBufferImpl_SetConeOrientation,
577         IDirectSound3DBufferImpl_SetConeOutsideVolume,
578         IDirectSound3DBufferImpl_SetMaxDistance,
579         IDirectSound3DBufferImpl_SetMinDistance,
580         IDirectSound3DBufferImpl_SetMode,
581         IDirectSound3DBufferImpl_SetPosition,
582         IDirectSound3DBufferImpl_SetVelocity,
583 };
584 #endif
585
586 #ifdef USE_DSOUND3D
587 static int DSOUND_Create3DBuffer(IDirectSoundBufferImpl* dsb)
588 {
589         DWORD   i, temp, iSize, oSize, offset;
590         LPBYTE  bIbuf, bObuf, bTbuf = NULL;
591         LPWORD  wIbuf, wObuf, wTbuf = NULL;
592
593         /* Inside DirectX says it's stupid but allowed */
594         if (dsb->wfx.nChannels == 2) {
595                 /* Convert to mono */
596                 if (dsb->wfx.wBitsPerSample == 16) {
597                         iSize = dsb->buflen / 4;
598                         wTbuf = malloc(dsb->buflen / 2);
599                         if (wTbuf == NULL)
600                                 return DSERR_OUTOFMEMORY;
601                         for (i = 0; i < iSize; i++)
602                                 wTbuf[i] = (dsb->buffer[i] + dsb->buffer[(i * 2) + 1]) / 2;
603                         wIbuf = wTbuf;
604                 } else {
605                         iSize = dsb->buflen / 2;
606                         bTbuf = malloc(dsb->buflen / 2);
607                         if (bTbuf == NULL)
608                                 return DSERR_OUTOFMEMORY;
609                         for (i = 0; i < iSize; i++)
610                                 bTbuf[i] = (dsb->buffer[i] + dsb->buffer[(i * 2) + 1]) / 2;
611                         bIbuf = bTbuf;
612                 }
613         } else {
614                 if (dsb->wfx.wBitsPerSample == 16) {
615                         iSize = dsb->buflen / 2;
616                         wIbuf = (LPWORD) dsb->buffer;
617                 } else {
618                         bIbuf = (LPBYTE) dsb->buffer;
619                         iSize = dsb->buflen;
620                 }
621         }
622
623         if (primarybuf->wfx.wBitsPerSample == 16) {
624                 wObuf = (LPWORD) dsb->ds3db->buffer;
625                 oSize = dsb->ds3db->buflen / 2;
626         } else {
627                 bObuf = (LPBYTE) dsb->ds3db->buffer;
628                 oSize = dsb->ds3db->buflen;
629         }
630
631         offset = primarybuf->wfx.nSamplesPerSec / 100;          /* 10ms */
632         if (primarybuf->wfx.wBitsPerSample == 16 && dsb->wfx.wBitsPerSample == 16)
633                 for (i = 0; i < iSize; i++) {
634                         temp = wIbuf[i];
635                         if (i >= offset)
636                                 temp += wIbuf[i - offset] >> 9;
637                         else
638                                 temp += wIbuf[i + iSize - offset] >> 9;
639                         wObuf[i * 2] = temp;
640                         wObuf[(i * 2) + 1] = temp;
641                 }
642         else if (primarybuf->wfx.wBitsPerSample == 8 && dsb->wfx.wBitsPerSample == 8)
643                 for (i = 0; i < iSize; i++) {
644                         temp = bIbuf[i];
645                         if (i >= offset)
646                                 temp += bIbuf[i - offset] >> 5;
647                         else
648                                 temp += bIbuf[i + iSize - offset] >> 5;
649                         bObuf[i * 2] = temp;
650                         bObuf[(i * 2) + 1] = temp;
651                 }
652         
653         if (wTbuf)
654                 free(wTbuf);
655         if (bTbuf)
656                 free(bTbuf);
657
658         return DS_OK;
659 }
660 #endif
661 /*******************************************************************************
662  *              IDirectSound3DListener
663  */
664
665 /* IUnknown methods */
666 static HRESULT WINAPI IDirectSound3DListenerImpl_QueryInterface(
667         LPDIRECTSOUND3DLISTENER iface, REFIID riid, LPVOID *ppobj)
668 {
669         ICOM_THIS(IDirectSound3DListenerImpl,iface);
670
671         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
672         return E_FAIL;
673 }
674         
675 static ULONG WINAPI IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface)
676 {
677         ICOM_THIS(IDirectSound3DListenerImpl,iface);
678         This->ref++;
679         return This->ref;
680 }
681
682 static ULONG WINAPI IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface)
683 {
684         ULONG ulReturn;
685         ICOM_THIS(IDirectSound3DListenerImpl,iface);
686
687         TRACE("(%p) ref was %ld\n", This, This->ref);
688
689         ulReturn = --This->ref;
690
691         /* Free all resources */
692         if( ulReturn == 0 ) {
693                 if(This->dsb)
694                         IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
695                 DeleteCriticalSection(&This->lock);
696                 HeapFree(GetProcessHeap(),0,This);
697         }
698
699         return ulReturn;
700 }
701
702 /* IDirectSound3DListener methods */
703 static HRESULT WINAPI IDirectSound3DListenerImpl_GetAllParameter(
704         LPDIRECTSOUND3DLISTENER iface,
705         LPDS3DLISTENER lpDS3DL)
706 {
707         FIXME("stub\n");
708         return DS_OK;
709 }
710
711 static HRESULT WINAPI IDirectSound3DListenerImpl_GetDistanceFactor(
712         LPDIRECTSOUND3DLISTENER iface,
713         LPD3DVALUE lpfDistanceFactor)
714 {
715         FIXME("stub\n");
716         return DS_OK;
717 }
718
719 static HRESULT WINAPI IDirectSound3DListenerImpl_GetDopplerFactor(
720         LPDIRECTSOUND3DLISTENER iface,
721         LPD3DVALUE lpfDopplerFactor)
722 {
723         FIXME("stub\n");
724         return DS_OK;
725 }
726
727 static HRESULT WINAPI IDirectSound3DListenerImpl_GetOrientation(
728         LPDIRECTSOUND3DLISTENER iface,
729         LPD3DVECTOR lpvOrientFront,
730         LPD3DVECTOR lpvOrientTop)
731 {
732         FIXME("stub\n");
733         return DS_OK;
734 }
735
736 static HRESULT WINAPI IDirectSound3DListenerImpl_GetPosition(
737         LPDIRECTSOUND3DLISTENER iface,
738         LPD3DVECTOR lpvPosition)
739 {
740         FIXME("stub\n");
741         return DS_OK;
742 }
743
744 static HRESULT WINAPI IDirectSound3DListenerImpl_GetRolloffFactor(
745         LPDIRECTSOUND3DLISTENER iface,
746         LPD3DVALUE lpfRolloffFactor)
747 {
748         FIXME("stub\n");
749         return DS_OK;
750 }
751
752 static HRESULT WINAPI IDirectSound3DListenerImpl_GetVelocity(
753         LPDIRECTSOUND3DLISTENER iface,
754         LPD3DVECTOR lpvVelocity)
755 {
756         FIXME("stub\n");
757         return DS_OK;
758 }
759
760 static HRESULT WINAPI IDirectSound3DListenerImpl_SetAllParameters(
761         LPDIRECTSOUND3DLISTENER iface,
762         LPCDS3DLISTENER lpcDS3DL,
763         DWORD dwApply)
764 {
765         FIXME("stub\n");
766         return DS_OK;
767 }
768
769 static HRESULT WINAPI IDirectSound3DListenerImpl_SetDistanceFactor(
770         LPDIRECTSOUND3DLISTENER iface,
771         D3DVALUE fDistanceFactor,
772         DWORD dwApply)
773 {
774         FIXME("stub\n");
775         return DS_OK;
776 }
777
778 static HRESULT WINAPI IDirectSound3DListenerImpl_SetDopplerFactor(
779         LPDIRECTSOUND3DLISTENER iface,
780         D3DVALUE fDopplerFactor,
781         DWORD dwApply)
782 {
783         FIXME("stub\n");
784         return DS_OK;
785 }
786
787 static HRESULT WINAPI IDirectSound3DListenerImpl_SetOrientation(
788         LPDIRECTSOUND3DLISTENER iface,
789         D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront,
790         D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop,
791         DWORD dwApply)
792 {
793         FIXME("stub\n");
794         return DS_OK;
795 }
796
797 static HRESULT WINAPI IDirectSound3DListenerImpl_SetPosition(
798         LPDIRECTSOUND3DLISTENER iface,
799         D3DVALUE x, D3DVALUE y, D3DVALUE z,
800         DWORD dwApply)
801 {
802         FIXME("stub\n");
803         return DS_OK;
804 }
805
806 static HRESULT WINAPI IDirectSound3DListenerImpl_SetRolloffFactor(
807         LPDIRECTSOUND3DLISTENER iface,
808         D3DVALUE fRolloffFactor,
809         DWORD dwApply)
810 {
811         FIXME("stub\n");
812         return DS_OK;
813 }
814
815 static HRESULT WINAPI IDirectSound3DListenerImpl_SetVelocity(
816         LPDIRECTSOUND3DLISTENER iface,
817         D3DVALUE x, D3DVALUE y, D3DVALUE z,
818         DWORD dwApply)
819 {
820         FIXME("stub\n");
821         return DS_OK;
822 }
823
824 static HRESULT WINAPI IDirectSound3DListenerImpl_CommitDeferredSettings(
825         LPDIRECTSOUND3DLISTENER iface)
826
827 {
828         FIXME("stub\n");
829         return DS_OK;
830 }
831
832 static ICOM_VTABLE(IDirectSound3DListener) ds3dlvt = 
833 {
834         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
835         /* IUnknown methods */
836         IDirectSound3DListenerImpl_QueryInterface,
837         IDirectSound3DListenerImpl_AddRef,
838         IDirectSound3DListenerImpl_Release,
839         /* IDirectSound3DListener methods */
840         IDirectSound3DListenerImpl_GetAllParameter,
841         IDirectSound3DListenerImpl_GetDistanceFactor,
842         IDirectSound3DListenerImpl_GetDopplerFactor,
843         IDirectSound3DListenerImpl_GetOrientation,
844         IDirectSound3DListenerImpl_GetPosition,
845         IDirectSound3DListenerImpl_GetRolloffFactor,
846         IDirectSound3DListenerImpl_GetVelocity,
847         IDirectSound3DListenerImpl_SetAllParameters,
848         IDirectSound3DListenerImpl_SetDistanceFactor,
849         IDirectSound3DListenerImpl_SetDopplerFactor,
850         IDirectSound3DListenerImpl_SetOrientation,
851         IDirectSound3DListenerImpl_SetPosition,
852         IDirectSound3DListenerImpl_SetRolloffFactor,
853         IDirectSound3DListenerImpl_SetVelocity,
854         IDirectSound3DListenerImpl_CommitDeferredSettings,
855 };
856
857 /*******************************************************************************
858  *              IDirectSoundNotify
859  */
860 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(
861         LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj
862 ) {
863         ICOM_THIS(IDirectSoundNotifyImpl,iface);
864
865         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
866         return E_FAIL;
867 }
868
869 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface) {
870         ICOM_THIS(IDirectSoundNotifyImpl,iface);
871         return ++(This->ref);
872 }
873
874 static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface) {
875         ICOM_THIS(IDirectSoundNotifyImpl,iface);
876
877         TRACE("(%p) ref was %ld\n", This, This->ref);
878
879         This->ref--;
880         if (!This->ref) {
881                 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
882                 HeapFree(GetProcessHeap(),0,This);
883                 return 0;
884         }
885         return This->ref;
886 }
887
888 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
889         LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
890 ) {
891         ICOM_THIS(IDirectSoundNotifyImpl,iface);
892         int     i;
893
894         if (TRACE_ON(dsound)) {
895             TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
896             for (i=0;i<howmuch;i++)
897                     TRACE("notify at %ld to 0x%08lx\n",
898                             notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
899         }
900         This->dsb->notifies = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->dsb->notifies,(This->dsb->nrofnotifies+howmuch)*sizeof(DSBPOSITIONNOTIFY));
901         memcpy( This->dsb->notifies+This->dsb->nrofnotifies,
902                 notify,
903                 howmuch*sizeof(DSBPOSITIONNOTIFY)
904         );
905         This->dsb->nrofnotifies+=howmuch;
906
907         return S_OK;
908 }
909
910 static ICOM_VTABLE(IDirectSoundNotify) dsnvt = 
911 {
912         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
913         IDirectSoundNotifyImpl_QueryInterface,
914         IDirectSoundNotifyImpl_AddRef,
915         IDirectSoundNotifyImpl_Release,
916         IDirectSoundNotifyImpl_SetNotificationPositions,
917 };
918
919 /*******************************************************************************
920  *              IDirectSoundBuffer
921  */
922
923 static void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan)
924 {
925         double temp;
926
927         /* the AmpFactors are expressed in 16.16 fixed point */
928         volpan->dwVolAmpFactor = (ULONG) (pow(2.0, volpan->lVolume / 600.0) * 65536);
929         /* FIXME: dwPan{Left|Right}AmpFactor */
930
931         /* FIXME: use calculated vol and pan ampfactors */
932         temp = (double) (volpan->lVolume - (volpan->lPan > 0 ? volpan->lPan : 0));
933         volpan->dwTotalLeftAmpFactor = (ULONG) (pow(2.0, temp / 600.0) * 65536);
934         temp = (double) (volpan->lVolume + (volpan->lPan < 0 ? volpan->lPan : 0));
935         volpan->dwTotalRightAmpFactor = (ULONG) (pow(2.0, temp / 600.0) * 65536);
936
937         TRACE("left = %lx, right = %lx\n", volpan->dwTotalLeftAmpFactor, volpan->dwTotalRightAmpFactor);
938 }
939
940 static void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
941 {
942         DWORD sw;
943
944         sw = dsb->wfx.nChannels * (dsb->wfx.wBitsPerSample / 8);
945         if ((dsb->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) && dsb->hwbuf) {
946                 DWORD fraglen;
947                 /* let fragment size approximate the timer delay */
948                 fraglen = (dsb->freq * DS_TIME_DEL / 1000) * sw;
949                 /* reduce fragment size until an integer number of them fits in the buffer */
950                 /* (FIXME: this may or may not be a good idea) */
951                 while (dsb->buflen % fraglen) fraglen -= sw;
952                 dsb->dsound->fraglen = fraglen;
953                 TRACE("fraglen=%ld\n", dsb->dsound->fraglen);
954         }
955         /* calculate the 10ms write lead */
956         dsb->writelead = (dsb->freq / 100) * sw;
957 }
958
959 static HRESULT DSOUND_PrimaryOpen(IDirectSoundBufferImpl *dsb)
960 {
961         HRESULT err = DS_OK;
962
963         /* are we using waveOut stuff? */
964         if (!dsb->hwbuf) {
965                 LPBYTE newbuf;
966                 DWORD buflen;
967                 HRESULT merr = DS_OK;
968                 /* Start in pause mode, to allow buffers to get filled */
969                 waveOutPause(dsb->dsound->hwo);
970                 /* use fragments of 10ms (1/100s) each (which should get us within
971                  * the documented write cursor lead of 10-15ms) */
972                 buflen = ((dsb->wfx.nAvgBytesPerSec / 100) & ~3) * DS_HEL_FRAGS;
973                 TRACE("desired buflen=%ld, old buffer=%p\n", buflen, dsb->buffer);
974                 /* reallocate emulated primary buffer */
975                 newbuf = (LPBYTE)HeapReAlloc(GetProcessHeap(),0,dsb->buffer,buflen);
976                 if (newbuf == NULL) {
977                         ERR("failed to allocate primary buffer\n");
978                         merr = DSERR_OUTOFMEMORY;
979                         /* but the old buffer might still exists and must be re-prepared */
980                 } else {
981                         dsb->buffer = newbuf;
982                         dsb->buflen = buflen;
983                 }
984                 if (dsb->buffer) {
985                         unsigned c;
986                         IDirectSoundImpl *ds = dsb->dsound;
987
988                         ds->fraglen = dsb->buflen / DS_HEL_FRAGS;
989
990                         /* prepare fragment headers */
991                         for (c=0; c<DS_HEL_FRAGS; c++) {
992                                 ds->pwave[c]->lpData = dsb->buffer + c*ds->fraglen;
993                                 ds->pwave[c]->dwBufferLength = ds->fraglen;
994                                 ds->pwave[c]->dwUser = (DWORD)dsb;
995                                 ds->pwave[c]->dwFlags = 0;
996                                 ds->pwave[c]->dwLoops = 0;
997                                 err = mmErr(waveOutPrepareHeader(ds->hwo,ds->pwave[c],sizeof(WAVEHDR)));
998                                 if (err != DS_OK) {
999                                         while (c--)
1000                                                 waveOutUnprepareHeader(ds->hwo,ds->pwave[c],sizeof(WAVEHDR));
1001                                         break;
1002                                 }
1003                         }
1004
1005                         ds->pwplay = 0;
1006                         ds->pwwrite = 0;
1007                         ds->pwqueue = 0;
1008                         memset(dsb->buffer, (dsb->wfx.wBitsPerSample == 16) ? 0 : 128, dsb->buflen);
1009                         TRACE("fraglen=%ld\n", ds->fraglen);
1010                 }
1011                 if ((err == DS_OK) && (merr != DS_OK))
1012                         err = merr;
1013         }
1014         return err;
1015 }
1016
1017
1018 static void DSOUND_PrimaryClose(IDirectSoundBufferImpl *dsb)
1019 {
1020         /* are we using waveOut stuff? */
1021         if (!dsb->hwbuf) {
1022                 unsigned c;
1023                 IDirectSoundImpl *ds = dsb->dsound;
1024
1025                 waveOutReset(ds->hwo);
1026                 for (c=0; c<DS_HEL_FRAGS; c++)
1027                         waveOutUnprepareHeader(ds->hwo, ds->pwave[c], sizeof(WAVEHDR));
1028         }
1029 }
1030
1031 /* This sets this format for the <em>Primary Buffer Only</em> */
1032 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
1033 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
1034         LPDIRECTSOUNDBUFFER iface,LPWAVEFORMATEX wfex
1035 ) {
1036         ICOM_THIS(IDirectSoundBufferImpl,iface);
1037         IDirectSoundBufferImpl** dsb;
1038         HRESULT err = DS_OK;
1039         int                     i;
1040
1041         /* Let's be pedantic! */
1042         if ((wfex == NULL) ||
1043             (wfex->wFormatTag != WAVE_FORMAT_PCM) ||
1044             (wfex->nChannels < 1) || (wfex->nChannels > 2) ||
1045             (wfex->nSamplesPerSec < 1) ||
1046             (wfex->nBlockAlign < 1) || (wfex->nChannels > 4) ||
1047             ((wfex->wBitsPerSample != 8) && (wfex->wBitsPerSample != 16))) {
1048                 TRACE("failed pedantic check!\n");
1049                 return DSERR_INVALIDPARAM;
1050         }
1051
1052         /* **** */
1053         EnterCriticalSection(&(This->dsound->lock));
1054
1055         if (primarybuf->wfx.nSamplesPerSec != wfex->nSamplesPerSec) {
1056                 dsb = dsound->buffers;
1057                 for (i = 0; i < dsound->nrofbuffers; i++, dsb++) {
1058                         /* **** */
1059                         EnterCriticalSection(&((*dsb)->lock));
1060
1061                         (*dsb)->freqAdjust = ((*dsb)->freq << DSOUND_FREQSHIFT) /
1062                                 wfex->nSamplesPerSec;
1063
1064                         LeaveCriticalSection(&((*dsb)->lock));
1065                         /* **** */
1066                 }
1067         }
1068
1069         memcpy(&(primarybuf->wfx), wfex, sizeof(primarybuf->wfx));
1070
1071         TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
1072                    "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1073                    wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
1074                    wfex->nAvgBytesPerSec, wfex->nBlockAlign, 
1075                    wfex->wBitsPerSample, wfex->cbSize);
1076
1077         primarybuf->wfx.nAvgBytesPerSec =
1078                 This->wfx.nSamplesPerSec * This->wfx.nBlockAlign;
1079         if (primarybuf->dsound->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMSETFORMAT) {
1080                 /* FIXME: check for errors */
1081                 DSOUND_PrimaryClose(primarybuf);
1082                 waveOutClose(This->dsound->hwo);
1083                 This->dsound->hwo = 0;
1084                 waveOutOpen(&(This->dsound->hwo), This->dsound->drvdesc.dnDevNode,
1085                             &(primarybuf->wfx), 0, 0, CALLBACK_NULL | WAVE_DIRECTSOUND);
1086                 DSOUND_PrimaryOpen(primarybuf);
1087         }
1088         if (primarybuf->hwbuf) {
1089                 err = IDsDriverBuffer_SetFormat(primarybuf->hwbuf, &(primarybuf->wfx));
1090                 if (err == DSERR_BUFFERLOST) {
1091                         /* Wine-only: the driver wants us to recreate the HW buffer */
1092                         IDsDriverBuffer_Release(primarybuf->hwbuf);
1093                         err = IDsDriver_CreateSoundBuffer(primarybuf->dsound->driver,&(primarybuf->wfx),primarybuf->dsbd.dwFlags,0,
1094                                                           &(primarybuf->buflen),&(primarybuf->buffer),
1095                                                           (LPVOID)&(primarybuf->hwbuf));
1096                 }
1097         }
1098         DSOUND_RecalcFormat(primarybuf);
1099
1100         LeaveCriticalSection(&(This->dsound->lock));
1101         /* **** */
1102
1103         return DS_OK;
1104 }
1105
1106 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
1107         LPDIRECTSOUNDBUFFER iface,LONG vol
1108 ) {
1109         ICOM_THIS(IDirectSoundBufferImpl,iface);
1110
1111         TRACE("(%p,%ld)\n",This,vol);
1112
1113         /* I'm not sure if we need this for primary buffer */
1114         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME))
1115                 return DSERR_CONTROLUNAVAIL;
1116
1117         if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN))
1118                 return DSERR_INVALIDPARAM;
1119
1120         /* **** */
1121         EnterCriticalSection(&(This->lock));
1122
1123         This->volpan.lVolume = vol;
1124
1125         DSOUND_RecalcVolPan(&(This->volpan));
1126
1127         if (This->hwbuf) {
1128                 IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
1129         }
1130         else if (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) {
1131 #if 0 /* should we really do this? */
1132                 /* the DS volume ranges from 0 (max, 0dB attenuation) to -10000 (min, 100dB attenuation) */
1133                 /* the MM volume ranges from 0 to 0xffff in an unspecified logarithmic scale */
1134                 WORD cvol = 0xffff + vol*6 + vol/2;
1135                 DWORD vol = cvol | ((DWORD)cvol << 16)
1136                 waveOutSetVolume(This->dsound->hwo, vol);
1137 #endif
1138         }
1139
1140         LeaveCriticalSection(&(This->lock));
1141         /* **** */
1142
1143         return DS_OK;
1144 }
1145
1146 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(
1147         LPDIRECTSOUNDBUFFER iface,LPLONG vol
1148 ) {
1149         ICOM_THIS(IDirectSoundBufferImpl,iface);
1150         TRACE("(%p,%p)\n",This,vol);
1151
1152         if (vol == NULL)
1153                 return DSERR_INVALIDPARAM;
1154
1155         *vol = This->volpan.lVolume;
1156         return DS_OK;
1157 }
1158
1159 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
1160         LPDIRECTSOUNDBUFFER iface,DWORD freq
1161 ) {
1162         ICOM_THIS(IDirectSoundBufferImpl,iface);
1163         TRACE("(%p,%ld)\n",This,freq);
1164
1165         /* You cannot set the frequency of the primary buffer */
1166         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY) ||
1167             (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER))
1168                 return DSERR_CONTROLUNAVAIL;
1169
1170         if (!freq) freq = This->wfx.nSamplesPerSec;
1171
1172         if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX))
1173                 return DSERR_INVALIDPARAM;
1174
1175         /* **** */
1176         EnterCriticalSection(&(This->lock));
1177
1178         This->freq = freq;
1179         This->freqAdjust = (freq << DSOUND_FREQSHIFT) / primarybuf->wfx.nSamplesPerSec;
1180         This->nAvgBytesPerSec = freq * This->wfx.nBlockAlign;
1181         DSOUND_RecalcFormat(This);
1182
1183         LeaveCriticalSection(&(This->lock));
1184         /* **** */
1185
1186         return DS_OK;
1187 }
1188
1189 static HRESULT WINAPI IDirectSoundBufferImpl_Play(
1190         LPDIRECTSOUNDBUFFER iface,DWORD reserved1,DWORD reserved2,DWORD flags
1191 ) {
1192         ICOM_THIS(IDirectSoundBufferImpl,iface);
1193         TRACE("(%p,%08lx,%08lx,%08lx)\n",
1194                 This,reserved1,reserved2,flags
1195         );
1196         This->playflags = flags;
1197         if (This->state == STATE_STOPPED) {
1198                 This->leadin = TRUE;
1199                 This->startpos = This->mixpos;
1200                 This->state = STATE_STARTING;
1201         } else if (This->state == STATE_STOPPING)
1202                 This->state = STATE_PLAYING;
1203         if (!(This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) && This->hwbuf) {
1204                 IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags);
1205                 This->state = STATE_PLAYING;
1206         }
1207         return DS_OK;
1208 }
1209
1210 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER iface)
1211 {
1212         ICOM_THIS(IDirectSoundBufferImpl,iface);
1213         TRACE("(%p)\n",This);
1214
1215         /* **** */
1216         EnterCriticalSection(&(This->lock));
1217
1218         if (This->state == STATE_PLAYING)
1219                 This->state = STATE_STOPPING;
1220         else if (This->state == STATE_STARTING)
1221                 This->state = STATE_STOPPED;
1222         if (!(This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) && This->hwbuf) {
1223                 IDsDriverBuffer_Stop(This->hwbuf);
1224                 This->state = STATE_STOPPED;
1225         }
1226         DSOUND_CheckEvent(This, 0);
1227
1228         LeaveCriticalSection(&(This->lock));
1229         /* **** */
1230
1231         return DS_OK;
1232 }
1233
1234 static DWORD WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER iface) {
1235         ICOM_THIS(IDirectSoundBufferImpl,iface);
1236         DWORD ref;
1237
1238         TRACE("(%p) ref was %ld, thread is %lx\n",This, This->ref, GetCurrentThreadId());
1239
1240         ref = InterlockedIncrement(&(This->ref));
1241         if (!ref) {
1242                 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
1243         }
1244         return ref;
1245 }
1246 static DWORD WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER iface) {
1247         ICOM_THIS(IDirectSoundBufferImpl,iface);
1248         int     i;
1249         DWORD ref;
1250
1251         TRACE("(%p) ref was %ld, thread is %lx\n",This, This->ref, GetCurrentThreadId());
1252
1253         ref = InterlockedDecrement(&(This->ref));
1254         if (ref) return ref;
1255
1256         EnterCriticalSection(&(This->dsound->lock));
1257         for (i=0;i<This->dsound->nrofbuffers;i++)
1258                 if (This->dsound->buffers[i] == This)
1259                         break;
1260
1261         if (i < This->dsound->nrofbuffers) {
1262                 /* Put the last buffer of the list in the (now empty) position */
1263                 This->dsound->buffers[i] = This->dsound->buffers[This->dsound->nrofbuffers - 1];
1264                 This->dsound->nrofbuffers--;
1265                 This->dsound->buffers = HeapReAlloc(GetProcessHeap(),0,This->dsound->buffers,sizeof(LPDIRECTSOUNDBUFFER)*This->dsound->nrofbuffers);
1266                 TRACE("buffer count is now %d\n", This->dsound->nrofbuffers);
1267                 IDirectSound_Release((LPDIRECTSOUND)This->dsound);
1268         }
1269         LeaveCriticalSection(&(This->dsound->lock));
1270
1271         DeleteCriticalSection(&(This->lock));
1272         if (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER)
1273                 DSOUND_PrimaryClose(This);
1274         if (This->hwbuf) {
1275                 IDsDriverBuffer_Release(This->hwbuf);
1276         }
1277         if (This->ds3db)
1278                 IDirectSound3DBuffer_Release((LPDIRECTSOUND3DBUFFER)This->ds3db);
1279         if (This->parent)
1280                 /* this is a duplicate buffer */
1281                 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->parent);
1282         else
1283                 /* this is a toplevel buffer */
1284                 HeapFree(GetProcessHeap(),0,This->buffer);
1285
1286         HeapFree(GetProcessHeap(),0,This);
1287         
1288         if (This == primarybuf)
1289                 primarybuf = NULL;
1290
1291         return 0;
1292 }
1293
1294 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
1295         LPDIRECTSOUNDBUFFER iface,LPDWORD playpos,LPDWORD writepos
1296 ) {
1297         ICOM_THIS(IDirectSoundBufferImpl,iface);
1298         TRACE("(%p,%p,%p)\n",This,playpos,writepos);
1299         if (This->hwbuf) {
1300                 IDsDriverBuffer_GetPosition(This->hwbuf, playpos, writepos);
1301         }
1302         else if (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) {
1303                 if (playpos && (This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2)) {
1304                         MMTIME mtime;
1305                         mtime.wType = TIME_BYTES;
1306                         waveOutGetPosition(This->dsound->hwo, &mtime, sizeof(mtime));
1307                         mtime.u.cb = mtime.u.cb % This->buflen;
1308                         *playpos = mtime.u.cb;
1309                 }
1310                 /* don't know how exactly non-GETCURRENTPOSITION2 behaves,
1311                  * but I think this works for Starcraft */
1312                 else if (playpos) *playpos = This->playpos;
1313                 if (writepos) {
1314                         /* the writepos should only be used by apps with WRITEPRIMARY priority,
1315                          * in which case our software mixer is disabled anyway */
1316                         *writepos = This->playpos + DS_HEL_MARGIN * This->dsound->fraglen;
1317                         while (*writepos >= This->buflen)
1318                                 *writepos -= This->buflen;
1319                 }
1320         } else {
1321                 if (playpos && (This->state != STATE_PLAYING)) {
1322                         /* we haven't been merged into the primary buffer (yet) */
1323                         *playpos = This->mixpos;
1324                 }
1325                 else if (playpos) {
1326                         DWORD pplay, lplay, splay, tplay, pstate;
1327                         /* let's get this exact; first, recursively call GetPosition on the primary */
1328                         EnterCriticalSection(&(primarybuf->lock));
1329                         if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || primarybuf->hwbuf) {
1330                                 IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER)primarybuf, &pplay, NULL);
1331                         } else {
1332                                 /* (unless the app isn't using GETCURRENTPOSITION2) */
1333                                 /* don't know exactly how this should be handled either */
1334                                 pplay = primarybuf->playpos;
1335                         }
1336                         /* get last mixed primary play position */
1337                         lplay = primarybuf->mixpos;
1338                         pstate = primarybuf->state;
1339                         /* detect HEL mode underrun */
1340                         if (!(primarybuf->hwbuf || primarybuf->dsound->pwqueue)) {
1341                                 TRACE("detected an underrun\n");
1342                                 pplay = lplay;
1343                                 if (pstate == STATE_PLAYING)
1344                                         pstate = STATE_STARTING;
1345                                 else if (pstate == STATE_STOPPING)
1346                                         pstate = STATE_STOPPED;
1347                         }
1348                         /* get our own last mixed position while we still have the lock */
1349                         splay = This->mixpos;
1350                         LeaveCriticalSection(&(primarybuf->lock));
1351                         TRACE("primary playpos=%ld, mixpos=%ld\n", pplay, lplay);
1352                         TRACE("this mixpos=%ld\n", splay);
1353
1354                         /* the actual primary play position (pplay) is always behind last mixed (lplay),
1355                          * unless the computer is too slow or something */
1356                         /* we need to know how far away we are from there */
1357                         if (lplay == pplay) {
1358                                 if ((pstate == STATE_PLAYING) || (pstate == STATE_STOPPING)) {
1359                                         /* wow, the software mixer is really doing well,
1360                                          * seems the entire primary buffer is filled! */
1361                                         lplay += primarybuf->buflen;
1362                                 }
1363                                 /* else: the primary buffer is not playing, so probably empty */
1364                         }
1365                         if (lplay < pplay) lplay += primarybuf->buflen; /* wraparound */
1366                         lplay -= pplay;
1367                         /* detect HAL mode underrun */
1368                         if (primarybuf->hwbuf &&
1369                             (lplay > ((DS_HAL_QUEUE + 1) * primarybuf->dsound->fraglen + primarybuf->writelead))) {
1370                                 TRACE("detected an underrun: primary queue was %ld\n",lplay);
1371                                 lplay = 0;
1372                         }
1373                         /* divide the offset by its sample size */
1374                         lplay /= primarybuf->wfx.nChannels * (primarybuf->wfx.wBitsPerSample / 8);
1375                         TRACE("primary back-samples=%ld\n",lplay);
1376                         /* adjust for our frequency */
1377                         lplay = (lplay * This->freqAdjust) >> DSOUND_FREQSHIFT;
1378                         /* multiply by our own sample size */
1379                         lplay *= This->wfx.nChannels * (This->wfx.wBitsPerSample / 8);
1380                         TRACE("this back-offset=%ld\n", lplay);
1381                         /* subtract from our last mixed position */
1382                         tplay = splay;
1383                         while (tplay < lplay) tplay += This->buflen; /* wraparound */
1384                         tplay -= lplay;
1385                         if (This->leadin && ((tplay < This->startpos) || (tplay > splay))) {
1386                                 /* seems we haven't started playing yet */
1387                                 TRACE("this still in lead-in phase\n");
1388                                 tplay = This->startpos;
1389                         }
1390                         /* return the result */
1391                         *playpos = tplay;
1392                 }
1393                 if (writepos) *writepos = This->mixpos;
1394         }
1395         if (writepos) {
1396                 if (This->state != STATE_STOPPED)
1397                         /* apply the documented 10ms lead to writepos */
1398                         *writepos += This->writelead;
1399                 while (*writepos >= This->buflen) *writepos -= This->buflen;
1400         }
1401         TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
1402         return DS_OK;
1403 }
1404
1405 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
1406         LPDIRECTSOUNDBUFFER iface,LPDWORD status
1407 ) {
1408         ICOM_THIS(IDirectSoundBufferImpl,iface);
1409         TRACE("(%p,%p), thread is %lx\n",This,status,GetCurrentThreadId());
1410
1411         if (status == NULL)
1412                 return DSERR_INVALIDPARAM;
1413
1414         *status = 0;
1415         if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING))
1416                 *status |= DSBSTATUS_PLAYING;
1417         if (This->playflags & DSBPLAY_LOOPING)
1418                 *status |= DSBSTATUS_LOOPING;
1419
1420         TRACE("status=%lx\n", *status);
1421         return DS_OK;
1422 }
1423
1424
1425 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
1426         LPDIRECTSOUNDBUFFER iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten
1427 ) {
1428         ICOM_THIS(IDirectSoundBufferImpl,iface);
1429         TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
1430
1431         if (wfsize>sizeof(This->wfx))
1432                 wfsize = sizeof(This->wfx);
1433         if (lpwf) {     /* NULL is valid */
1434                 memcpy(lpwf,&(This->wfx),wfsize);
1435                 if (wfwritten)
1436                         *wfwritten = wfsize;
1437         } else
1438                 if (wfwritten)
1439                         *wfwritten = sizeof(This->wfx);
1440                 else
1441                         return DSERR_INVALIDPARAM;
1442
1443         return DS_OK;
1444 }
1445
1446 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
1447         LPDIRECTSOUNDBUFFER iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
1448 ) {
1449         ICOM_THIS(IDirectSoundBufferImpl,iface);
1450         DWORD capf;
1451
1452         TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1453                 This,
1454                 writecursor,
1455                 writebytes,
1456                 lplpaudioptr1,
1457                 audiobytes1,
1458                 lplpaudioptr2,
1459                 audiobytes2,
1460                 flags
1461         );
1462
1463         if (flags & DSBLOCK_FROMWRITECURSOR) {
1464                 DWORD writepos;
1465                 /* GetCurrentPosition does too much magic to duplicate here */
1466                 IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writepos);
1467                 writecursor += writepos;
1468         }
1469         if (flags & DSBLOCK_ENTIREBUFFER)
1470                 writebytes = This->buflen;
1471         if (writebytes > This->buflen)
1472                 writebytes = This->buflen;
1473
1474         assert(audiobytes1!=audiobytes2);
1475         assert(lplpaudioptr1!=lplpaudioptr2);
1476
1477         if (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER)
1478                 capf = DSDDESC_DONTNEEDPRIMARYLOCK;
1479         else
1480                 capf = DSDDESC_DONTNEEDSECONDARYLOCK;
1481         if (!(This->dsound->drvdesc.dwFlags & capf) && This->hwbuf) {
1482                 IDsDriverBuffer_Lock(This->hwbuf,
1483                                      lplpaudioptr1, audiobytes1,
1484                                      lplpaudioptr2, audiobytes2,
1485                                      writecursor, writebytes,
1486                                      0);
1487         } else
1488         if (writecursor+writebytes <= This->buflen) {
1489                 *(LPBYTE*)lplpaudioptr1 = This->buffer+writecursor;
1490                 *audiobytes1 = writebytes;
1491                 if (lplpaudioptr2)
1492                         *(LPBYTE*)lplpaudioptr2 = NULL;
1493                 if (audiobytes2)
1494                         *audiobytes2 = 0;
1495                 TRACE("->%ld.0\n",writebytes);
1496         } else {
1497                 *(LPBYTE*)lplpaudioptr1 = This->buffer+writecursor;
1498                 *audiobytes1 = This->buflen-writecursor;
1499                 if (lplpaudioptr2)
1500                         *(LPBYTE*)lplpaudioptr2 = This->buffer;
1501                 if (audiobytes2)
1502                         *audiobytes2 = writebytes-(This->buflen-writecursor);
1503                 TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
1504         }
1505         return DS_OK;
1506 }
1507
1508 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
1509         LPDIRECTSOUNDBUFFER iface,DWORD newpos
1510 ) {
1511         ICOM_THIS(IDirectSoundBufferImpl,iface);
1512         TRACE("(%p,%ld)\n",This,newpos);
1513
1514         /* **** */
1515         EnterCriticalSection(&(This->lock));
1516
1517         This->mixpos = newpos;
1518         if (This->hwbuf)
1519                 IDsDriverBuffer_SetPosition(This->hwbuf, This->mixpos);
1520
1521         LeaveCriticalSection(&(This->lock));
1522         /* **** */
1523
1524         return DS_OK;
1525 }
1526
1527 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
1528         LPDIRECTSOUNDBUFFER iface,LONG pan
1529 ) {
1530         ICOM_THIS(IDirectSoundBufferImpl,iface);
1531
1532         TRACE("(%p,%ld)\n",This,pan);
1533
1534         if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT))
1535                 return DSERR_INVALIDPARAM;
1536
1537         /* You cannot set the pan of the primary buffer */
1538         /* and you cannot use both pan and 3D controls */
1539         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
1540             (This->dsbd.dwFlags & DSBCAPS_CTRL3D) ||
1541             (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER))
1542                 return DSERR_CONTROLUNAVAIL;
1543
1544         /* **** */
1545         EnterCriticalSection(&(This->lock));
1546
1547         This->volpan.lPan = pan;
1548
1549         DSOUND_RecalcVolPan(&(This->volpan));
1550
1551         if (This->hwbuf) {
1552                 IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
1553         }
1554
1555         LeaveCriticalSection(&(This->lock));
1556         /* **** */
1557
1558         return DS_OK;
1559 }
1560
1561 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
1562         LPDIRECTSOUNDBUFFER iface,LPLONG pan
1563 ) {
1564         ICOM_THIS(IDirectSoundBufferImpl,iface);
1565         TRACE("(%p,%p)\n",This,pan);
1566
1567         if (pan == NULL)
1568                 return DSERR_INVALIDPARAM;
1569
1570         *pan = This->volpan.lPan;
1571
1572         return DS_OK;
1573 }
1574
1575 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
1576         LPDIRECTSOUNDBUFFER iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
1577 ) {
1578         ICOM_THIS(IDirectSoundBufferImpl,iface);
1579         DWORD capf;
1580
1581         TRACE("(%p,%p,%ld,%p,%ld):stub\n", This,p1,x1,p2,x2);
1582
1583 #if 0
1584         /* Preprocess 3D buffers... */
1585
1586         /* This is highly experimental and liable to break things */
1587         if (This->dsbd.dwFlags & DSBCAPS_CTRL3D)
1588                 DSOUND_Create3DBuffer(This);
1589 #endif
1590
1591         if (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER)
1592                 capf = DSDDESC_DONTNEEDPRIMARYLOCK;
1593         else
1594                 capf = DSDDESC_DONTNEEDSECONDARYLOCK;
1595         if (!(This->dsound->drvdesc.dwFlags & capf) && This->hwbuf) {
1596                 IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
1597         }
1598
1599         return DS_OK;
1600 }
1601
1602 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(
1603         LPDIRECTSOUNDBUFFER iface
1604 ) {
1605         ICOM_THIS(IDirectSoundBufferImpl,iface);
1606         FIXME("(%p):stub\n",This);
1607         return DS_OK;
1608 }
1609
1610 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
1611         LPDIRECTSOUNDBUFFER iface,LPDWORD freq
1612 ) {
1613         ICOM_THIS(IDirectSoundBufferImpl,iface);
1614         TRACE("(%p,%p)\n",This,freq);
1615
1616         if (freq == NULL)
1617                 return DSERR_INVALIDPARAM;
1618
1619         *freq = This->freq;
1620         TRACE("-> %ld\n", *freq);
1621
1622         return DS_OK;
1623 }
1624
1625 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
1626         LPDIRECTSOUNDBUFFER iface,LPDIRECTSOUND dsound,LPDSBUFFERDESC dbsd
1627 ) {
1628         ICOM_THIS(IDirectSoundBufferImpl,iface);
1629         FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
1630         DPRINTF("Re-Init!!!\n");
1631         return DSERR_ALREADYINITIALIZED;
1632 }
1633
1634 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
1635         LPDIRECTSOUNDBUFFER iface,LPDSBCAPS caps
1636 ) {
1637         ICOM_THIS(IDirectSoundBufferImpl,iface);
1638         TRACE("(%p)->(%p)\n",This,caps);
1639   
1640         if (caps == NULL)
1641                 return DSERR_INVALIDPARAM;
1642
1643         /* I think we should check this value, not set it. See */
1644         /* Inside DirectX, p215. That should apply here, too. */
1645         caps->dwSize = sizeof(*caps);
1646
1647         caps->dwFlags = This->dsbd.dwFlags;
1648         if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
1649         else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
1650
1651         caps->dwBufferBytes = This->dsbd.dwBufferBytes;
1652
1653         /* This value represents the speed of the "unlock" command.
1654            As unlock is quite fast (it does not do anything), I put
1655            4096 ko/s = 4 Mo / s */
1656         /* FIXME: hwbuf speed */
1657         caps->dwUnlockTransferRate = 4096;
1658         caps->dwPlayCpuOverhead = 0;
1659
1660         return DS_OK;
1661 }
1662
1663 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
1664         LPDIRECTSOUNDBUFFER iface,REFIID riid,LPVOID *ppobj
1665 ) {
1666         ICOM_THIS(IDirectSoundBufferImpl,iface);
1667
1668         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1669
1670         if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
1671                 IDirectSoundNotifyImpl  *dsn;
1672
1673                 dsn = (IDirectSoundNotifyImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn));
1674                 dsn->ref = 1;
1675                 dsn->dsb = This;
1676                 IDirectSoundBuffer_AddRef(iface);
1677                 ICOM_VTBL(dsn) = &dsnvt;
1678                 *ppobj = (LPVOID)dsn;
1679                 return S_OK;
1680         }
1681
1682 #if USE_DSOUND3D
1683         if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
1684                 IDirectSound3DBufferImpl        *ds3db;
1685
1686                 *ppobj = This->ds3db;
1687                 if (*ppobj) {
1688                         IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
1689                         return S_OK;
1690                 }
1691
1692                 ds3db = (IDirectSound3DBufferImpl*)HeapAlloc(GetProcessHeap(),
1693                         0,sizeof(*ds3db));
1694                 ds3db->ref = 1;
1695                 ds3db->dsb = (*ippdsb);
1696                 ICOM_VTBL(ds3db) = &ds3dbvt;
1697                 InitializeCriticalSection(&ds3db->lock);
1698
1699                 ds3db->ds3db = This;
1700                 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)This);
1701
1702                 ds3db->ds3db.dwSize = sizeof(DS3DBUFFER);
1703                 ds3db->ds3db.vPosition.x.x = 0.0;
1704                 ds3db->ds3db.vPosition.y.y = 0.0;
1705                 ds3db->ds3db.vPosition.z.z = 0.0;
1706                 ds3db->ds3db.vVelocity.x.x = 0.0;
1707                 ds3db->ds3db.vVelocity.y.y = 0.0;
1708                 ds3db->ds3db.vVelocity.z.z = 0.0;
1709                 ds3db->ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1710                 ds3db->ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1711                 ds3db->ds3db.vConeOrientation.x.x = 0.0;
1712                 ds3db->ds3db.vConeOrientation.y.y = 0.0;
1713                 ds3db->ds3db.vConeOrientation.z.z = 0.0;
1714                 ds3db->ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;                ds3db->ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
1715                 ds3db->ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1716                 ds3db->ds3db.dwMode = DS3DMODE_NORMAL;
1717                 ds3db->buflen = ((*ippdsb)->buflen * primarybuf->wfx.nBlockAlign) /
1718                         (*ippdsb)->wfx.nBlockAlign;
1719                 ds3db->buffer = HeapAlloc(GetProcessHeap(), 0, ds3db->buflen);
1720                 if (ds3db->buffer == NULL) {
1721                         ds3db->buflen = 0;
1722                         ds3db->ds3db.dwMode = DS3DMODE_DISABLE;
1723                 }
1724
1725                 return S_OK;
1726         }
1727 #endif
1728
1729         if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
1730                 IDirectSound3DListenerImpl* dsl;
1731
1732                 if (This->dsound->listener) {
1733                         *ppobj = This->dsound->listener;
1734                         IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)This->dsound->listener);
1735                         return DS_OK;
1736                 }
1737
1738                 dsl = (IDirectSound3DListenerImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsl));
1739                 dsl->ref = 1;
1740                 ICOM_VTBL(dsl) = &ds3dlvt;
1741                 *ppobj = (LPVOID)dsl;
1742
1743                 dsl->ds3dl.dwSize = sizeof(DS3DLISTENER);
1744                 dsl->ds3dl.vPosition.u1.x = 0.0;
1745                 dsl->ds3dl.vPosition.u2.y = 0.0;
1746                 dsl->ds3dl.vPosition.u3.z = 0.0;
1747                 dsl->ds3dl.vVelocity.u1.x = 0.0;
1748                 dsl->ds3dl.vVelocity.u2.y = 0.0;
1749                 dsl->ds3dl.vVelocity.u3.z = 0.0;
1750                 dsl->ds3dl.vOrientFront.u1.x = 0.0;
1751                 dsl->ds3dl.vOrientFront.u2.y = 0.0;
1752                 dsl->ds3dl.vOrientFront.u3.z = 1.0;
1753                 dsl->ds3dl.vOrientTop.u1.x = 0.0;
1754                 dsl->ds3dl.vOrientTop.u2.y = 1.0;
1755                 dsl->ds3dl.vOrientTop.u3.z = 0.0;
1756                 dsl->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
1757                 dsl->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
1758
1759                 InitializeCriticalSection(&dsl->lock);
1760
1761                 dsl->dsb = This;
1762                 IDirectSoundBuffer_AddRef(iface);
1763
1764                 This->dsound->listener = dsl;
1765                 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)dsl);
1766
1767                 return S_OK;
1768         }
1769
1770         FIXME( "Unknown GUID %s\n", debugstr_guid( riid ) );
1771
1772         *ppobj = NULL;
1773
1774         return E_FAIL;
1775 }
1776
1777 static ICOM_VTABLE(IDirectSoundBuffer) dsbvt = 
1778 {
1779         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1780         IDirectSoundBufferImpl_QueryInterface,
1781         IDirectSoundBufferImpl_AddRef,
1782         IDirectSoundBufferImpl_Release,
1783         IDirectSoundBufferImpl_GetCaps,
1784         IDirectSoundBufferImpl_GetCurrentPosition,
1785         IDirectSoundBufferImpl_GetFormat,
1786         IDirectSoundBufferImpl_GetVolume,
1787         IDirectSoundBufferImpl_GetPan,
1788         IDirectSoundBufferImpl_GetFrequency,
1789         IDirectSoundBufferImpl_GetStatus,
1790         IDirectSoundBufferImpl_Initialize,
1791         IDirectSoundBufferImpl_Lock,
1792         IDirectSoundBufferImpl_Play,
1793         IDirectSoundBufferImpl_SetCurrentPosition,
1794         IDirectSoundBufferImpl_SetFormat,
1795         IDirectSoundBufferImpl_SetVolume,
1796         IDirectSoundBufferImpl_SetPan,
1797         IDirectSoundBufferImpl_SetFrequency,
1798         IDirectSoundBufferImpl_Stop,
1799         IDirectSoundBufferImpl_Unlock,
1800         IDirectSoundBufferImpl_Restore
1801 };
1802
1803 /*******************************************************************************
1804  *              IDirectSound
1805  */
1806
1807 static HRESULT WINAPI IDirectSoundImpl_SetCooperativeLevel(
1808         LPDIRECTSOUND iface,HWND hwnd,DWORD level
1809 ) {
1810         ICOM_THIS(IDirectSoundImpl,iface);
1811
1812         FIXME("(%p,%08lx,%ld):stub\n",This,(DWORD)hwnd,level);
1813
1814         This->priolevel = level;
1815
1816         return DS_OK;
1817 }
1818
1819 static HRESULT WINAPI IDirectSoundImpl_CreateSoundBuffer(
1820         LPDIRECTSOUND iface,LPDSBUFFERDESC dsbd,LPLPDIRECTSOUNDBUFFER ppdsb,LPUNKNOWN lpunk
1821 ) {
1822         ICOM_THIS(IDirectSoundImpl,iface);
1823         IDirectSoundBufferImpl** ippdsb=(IDirectSoundBufferImpl**)ppdsb;
1824         LPWAVEFORMATEX  wfex;
1825         HRESULT err = DS_OK;
1826
1827         TRACE("(%p,%p,%p,%p)\n",This,dsbd,ippdsb,lpunk);
1828         
1829         if ((This == NULL) || (dsbd == NULL) || (ippdsb == NULL))
1830                 return DSERR_INVALIDPARAM;
1831         
1832         if (TRACE_ON(dsound)) {
1833                 TRACE("(structsize=%ld)\n",dsbd->dwSize);
1834                 TRACE("(flags=0x%08lx:\n",dsbd->dwFlags);
1835                 _dump_DSBCAPS(dsbd->dwFlags);
1836                 DPRINTF(")\n");
1837                 TRACE("(bufferbytes=%ld)\n",dsbd->dwBufferBytes);
1838                 TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
1839         }
1840
1841         wfex = dsbd->lpwfxFormat;
1842
1843         if (wfex)
1844                 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
1845                    "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1846                    wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
1847                    wfex->nAvgBytesPerSec, wfex->nBlockAlign, 
1848                    wfex->wBitsPerSample, wfex->cbSize);
1849
1850         if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1851                 if (primarybuf) {
1852                         IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)primarybuf);
1853                         *ippdsb = primarybuf;
1854                         primarybuf->dsbd.dwFlags = dsbd->dwFlags;
1855                         return DS_OK;
1856                 } /* Else create primary buffer */
1857         }
1858
1859         *ippdsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundBufferImpl));
1860         if (*ippdsb == NULL)
1861                 return DSERR_OUTOFMEMORY;
1862         ICOM_VTBL(*ippdsb) = &dsbvt;
1863         (*ippdsb)->ref = 1;
1864         (*ippdsb)->dsound = This;
1865         (*ippdsb)->parent = NULL;
1866         (*ippdsb)->buffer = NULL;
1867
1868         memcpy(&((*ippdsb)->dsbd),dsbd,sizeof(*dsbd));
1869         if (dsbd->lpwfxFormat)
1870                 memcpy(&((*ippdsb)->wfx), dsbd->lpwfxFormat, sizeof((*ippdsb)->wfx));
1871
1872         TRACE("Created buffer at %p\n", *ippdsb);
1873
1874         if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1875                 (*ippdsb)->buflen = dsound->wfx.nAvgBytesPerSec;
1876                 (*ippdsb)->freq = dsound->wfx.nSamplesPerSec;
1877
1878                 /* FIXME: verify that hardware capabilities (DSCAPS_PRIMARY flags) match */
1879
1880                 if (This->driver) {
1881                         err = IDsDriver_CreateSoundBuffer(This->driver,wfex,dsbd->dwFlags,0,
1882                                                           &((*ippdsb)->buflen),&((*ippdsb)->buffer),
1883                                                           (LPVOID*)&((*ippdsb)->hwbuf));
1884                 }
1885                 if (err == DS_OK)
1886                         err = DSOUND_PrimaryOpen(*ippdsb);
1887         } else {
1888                 DWORD capf = 0;
1889                 int use_hw;
1890
1891                 (*ippdsb)->buflen = dsbd->dwBufferBytes;
1892                 (*ippdsb)->freq = dsbd->lpwfxFormat->nSamplesPerSec;
1893
1894                 /* Check necessary hardware mixing capabilities */
1895                 if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
1896                 else capf |= DSCAPS_SECONDARYMONO;
1897                 if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
1898                 else capf |= DSCAPS_SECONDARY8BIT;
1899                 use_hw = (This->drvcaps.dwFlags & capf) == capf;
1900
1901                 /* FIXME: check hardware sample rate mixing capabilities */
1902                 /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
1903                 /* FIXME: check whether any hardware buffers are left */
1904                 /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
1905
1906                 /* Allocate system memory if applicable */
1907                 if ((This->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
1908                         (*ippdsb)->buffer = (LPBYTE)HeapAlloc(GetProcessHeap(),0,(*ippdsb)->buflen);
1909                         if ((*ippdsb)->buffer == NULL)
1910                                 err = DSERR_OUTOFMEMORY;
1911                 }
1912
1913                 /* Allocate the hardware buffer */
1914                 if (use_hw && (err == DS_OK)) {
1915                         err = IDsDriver_CreateSoundBuffer(This->driver,wfex,dsbd->dwFlags,0,
1916                                                           &((*ippdsb)->buflen),&((*ippdsb)->buffer),
1917                                                           (LPVOID*)&((*ippdsb)->hwbuf));
1918                 }
1919         }
1920
1921         if (err != DS_OK) {
1922                 if ((*ippdsb)->buffer)
1923                         HeapFree(GetProcessHeap(),0,(*ippdsb)->buffer);
1924                 HeapFree(GetProcessHeap(),0,(*ippdsb));
1925                 *ippdsb = NULL;
1926                 return err;
1927         }
1928         /* calculate fragment size and write lead */
1929         DSOUND_RecalcFormat(*ippdsb);
1930
1931         /* It's not necessary to initialize values to zero since */
1932         /* we allocated this structure with HEAP_ZERO_MEMORY... */
1933         (*ippdsb)->playpos = 0;
1934         (*ippdsb)->mixpos = 0;
1935         (*ippdsb)->state = STATE_STOPPED;
1936         DSOUND_RecalcVolPan(&((*ippdsb)->volpan));
1937
1938         if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1939                 (*ippdsb)->freqAdjust = ((*ippdsb)->freq << DSOUND_FREQSHIFT) /
1940                         primarybuf->wfx.nSamplesPerSec;
1941                 (*ippdsb)->nAvgBytesPerSec = (*ippdsb)->freq *
1942                         dsbd->lpwfxFormat->nBlockAlign;
1943         }
1944
1945         EnterCriticalSection(&(This->lock));
1946         /* register buffer */
1947         if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1948                 IDirectSoundBufferImpl **newbuffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl*)*(This->nrofbuffers+1));
1949                 if (newbuffers) {
1950                         This->buffers = newbuffers;
1951                         This->buffers[This->nrofbuffers] = *ippdsb;
1952                         This->nrofbuffers++;
1953                         TRACE("buffer count is now %d\n", This->nrofbuffers);
1954                 } else {
1955                         ERR("out of memory for buffer list! Current buffer count is %d\n", This->nrofbuffers);
1956                         err = DSERR_OUTOFMEMORY;
1957                 }
1958         }
1959         LeaveCriticalSection(&(This->lock));
1960
1961         IDirectSound_AddRef(iface);
1962
1963         InitializeCriticalSection(&((*ippdsb)->lock));
1964
1965         if (err != DS_OK) {
1966                 /* oops... */
1967                 IDirectSoundBuffer_Release(*ppdsb);
1968                 *ippdsb = NULL;
1969                 return err;
1970         }
1971         
1972 #if USE_DSOUND3D
1973         if (dsbd->dwFlags & DSBCAPS_CTRL3D) {
1974                 IDirectSound3DBufferImpl        *ds3db;
1975
1976                 ds3db = (IDirectSound3DBufferImpl*)HeapAlloc(GetProcessHeap(),
1977                         0,sizeof(*ds3db));
1978                 ICOM_VTBL(ds3db) = &ds3dbvt;
1979                 ds3db->ref = 1;
1980                 (*ippdsb)->ds3db = ds3db;
1981
1982                 ds3db->dsb = (*ippdsb);
1983                 IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER)ippdsb);
1984
1985                 InitializeCriticalSection(&ds3db->lock);
1986
1987                 ds3db->ds3db.dwSize = sizeof(DS3DBUFFER);
1988                 ds3db->ds3db.vPosition.x.x = 0.0;
1989                 ds3db->ds3db.vPosition.y.y = 0.0;
1990                 ds3db->ds3db.vPosition.z.z = 0.0;
1991                 ds3db->ds3db.vVelocity.x.x = 0.0;
1992                 ds3db->ds3db.vVelocity.y.y = 0.0;
1993                 ds3db->ds3db.vVelocity.z.z = 0.0;
1994                 ds3db->ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1995                 ds3db->ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1996                 ds3db->ds3db.vConeOrientation.x.x = 0.0;
1997                 ds3db->ds3db.vConeOrientation.y.y = 0.0;
1998                 ds3db->ds3db.vConeOrientation.z.z = 0.0;
1999                 ds3db->ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
2000                 ds3db->ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
2001                 ds3db->ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
2002                 ds3db->ds3db.dwMode = DS3DMODE_NORMAL;
2003                 ds3db->buflen = ((*ippdsb)->buflen * primarybuf->wfx.nBlockAlign) /
2004                         (*ippdsb)->wfx.nBlockAlign;
2005                 ds3db->buffer = HeapAlloc(GetProcessHeap(), 0, ds3db->buflen);
2006                 if (ds3db->buffer == NULL) {
2007                         ds3db->buflen = 0;
2008                         ds3db->ds3db.dwMode = DS3DMODE_DISABLE;
2009                 }
2010         }
2011 #endif
2012         return DS_OK;
2013 }
2014
2015 static HRESULT WINAPI IDirectSoundImpl_DuplicateSoundBuffer(
2016         LPDIRECTSOUND iface,LPDIRECTSOUNDBUFFER pdsb,LPLPDIRECTSOUNDBUFFER ppdsb
2017 ) {
2018         ICOM_THIS(IDirectSoundImpl,iface);
2019         IDirectSoundBufferImpl* ipdsb=(IDirectSoundBufferImpl*)pdsb;
2020         IDirectSoundBufferImpl** ippdsb=(IDirectSoundBufferImpl**)ppdsb;
2021         TRACE("(%p,%p,%p)\n",This,ipdsb,ippdsb);
2022
2023         if (ipdsb->hwbuf) {
2024                 FIXME("need to duplicate hardware buffer\n");
2025         }
2026
2027         *ippdsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundBufferImpl));
2028
2029         IDirectSoundBuffer_AddRef(pdsb);
2030         memcpy(*ippdsb, ipdsb, sizeof(IDirectSoundBufferImpl));
2031         (*ippdsb)->ref = 1;
2032         (*ippdsb)->playpos = 0;
2033         (*ippdsb)->mixpos = 0;
2034         (*ippdsb)->dsound = This;
2035         (*ippdsb)->parent = ipdsb;
2036         memcpy(&((*ippdsb)->wfx), &(ipdsb->wfx), sizeof((*ippdsb)->wfx));
2037         InitializeCriticalSection(&(*ippdsb)->lock);
2038         /* register buffer */
2039         EnterCriticalSection(&(This->lock));
2040         {
2041                 IDirectSoundBufferImpl **newbuffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl**)*(This->nrofbuffers+1));
2042                 if (newbuffers) {
2043                         This->buffers = newbuffers;
2044                         This->buffers[This->nrofbuffers] = *ippdsb;
2045                         This->nrofbuffers++;
2046                         TRACE("buffer count is now %d\n", This->nrofbuffers);
2047                 } else {
2048                         ERR("out of memory for buffer list! Current buffer count is %d\n", This->nrofbuffers);
2049                         /* FIXME: release buffer */
2050                 }
2051         }
2052         LeaveCriticalSection(&(This->lock));
2053         IDirectSound_AddRef(iface);
2054         return DS_OK;
2055 }
2056
2057
2058 static HRESULT WINAPI IDirectSoundImpl_GetCaps(LPDIRECTSOUND iface,LPDSCAPS caps) {
2059         ICOM_THIS(IDirectSoundImpl,iface);
2060         TRACE("(%p,%p)\n",This,caps);
2061         TRACE("(flags=0x%08lx)\n",caps->dwFlags);
2062
2063         if (caps == NULL)
2064                 return DSERR_INVALIDPARAM;
2065
2066         /* We should check this value, not set it. See Inside DirectX, p215. */
2067         caps->dwSize = sizeof(*caps);
2068
2069         caps->dwFlags = This->drvcaps.dwFlags;
2070
2071         /* FIXME: copy caps from This->drvcaps */
2072         caps->dwMinSecondarySampleRate          = DSBFREQUENCY_MIN;
2073         caps->dwMaxSecondarySampleRate          = DSBFREQUENCY_MAX;
2074
2075         caps->dwPrimaryBuffers                  = 1;
2076
2077         caps->dwMaxHwMixingAllBuffers           = 0;
2078         caps->dwMaxHwMixingStaticBuffers        = 0;
2079         caps->dwMaxHwMixingStreamingBuffers     = 0;
2080
2081         caps->dwFreeHwMixingAllBuffers          = 0;
2082         caps->dwFreeHwMixingStaticBuffers       = 0;
2083         caps->dwFreeHwMixingStreamingBuffers    = 0;
2084
2085         caps->dwMaxHw3DAllBuffers               = 0;
2086         caps->dwMaxHw3DStaticBuffers            = 0;
2087         caps->dwMaxHw3DStreamingBuffers         = 0;
2088
2089         caps->dwFreeHw3DAllBuffers              = 0;
2090         caps->dwFreeHw3DStaticBuffers           = 0;
2091         caps->dwFreeHw3DStreamingBuffers        = 0;
2092
2093         caps->dwTotalHwMemBytes                 = 0;
2094
2095         caps->dwFreeHwMemBytes                  = 0;
2096
2097         caps->dwMaxContigFreeHwMemBytes         = 0;
2098
2099         caps->dwUnlockTransferRateHwBuffers     = 4096; /* But we have none... */
2100
2101         caps->dwPlayCpuOverheadSwBuffers        = 1;    /* 1% */
2102
2103         return DS_OK;
2104 }
2105
2106 static ULONG WINAPI IDirectSoundImpl_AddRef(LPDIRECTSOUND iface) {
2107         ICOM_THIS(IDirectSoundImpl,iface);
2108         return ++(This->ref);
2109 }
2110
2111 static ULONG WINAPI IDirectSoundImpl_Release(LPDIRECTSOUND iface) {
2112         ICOM_THIS(IDirectSoundImpl,iface);
2113         TRACE("(%p), ref was %ld\n",This,This->ref);
2114         if (!--(This->ref)) {
2115                 UINT i;
2116
2117                 timeKillEvent(This->timerID);
2118                 timeEndPeriod(DS_TIME_RES);
2119
2120                 if (primarybuf)
2121                         IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)primarybuf);
2122
2123                 if (This->buffers) {
2124                         for( i=0;i<This->nrofbuffers;i++)       
2125                                 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->buffers[i]);
2126                 }
2127
2128                 if (This->primary)
2129                         IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->primary);
2130
2131                 DeleteCriticalSection(&This->lock);
2132                 if (This->driver) {
2133                         IDsDriver_Close(This->driver);
2134                 } else {
2135                         unsigned c;
2136                         for (c=0; c<DS_HEL_FRAGS; c++)
2137                                 HeapFree(GetProcessHeap(),0,This->pwave[c]);
2138                 }
2139                 if (This->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) {
2140                         waveOutClose(This->hwo);
2141                 }
2142                 if (This->driver)
2143                         IDsDriver_Release(This->driver);
2144
2145                 HeapFree(GetProcessHeap(),0,This);
2146                 dsound = NULL;
2147                 return 0;
2148         }
2149         return This->ref;
2150 }
2151
2152 static HRESULT WINAPI IDirectSoundImpl_SetSpeakerConfig(
2153         LPDIRECTSOUND iface,DWORD config
2154 ) {
2155         ICOM_THIS(IDirectSoundImpl,iface);
2156         FIXME("(%p,0x%08lx):stub\n",This,config);
2157         return DS_OK;
2158 }
2159
2160 static HRESULT WINAPI IDirectSoundImpl_QueryInterface(
2161         LPDIRECTSOUND iface,REFIID riid,LPVOID *ppobj
2162 ) {
2163         ICOM_THIS(IDirectSoundImpl,iface);
2164
2165         if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
2166
2167                 if (This->listener) {
2168                         *ppobj = This->listener;
2169                         IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)This->listener);
2170                         return DS_OK;
2171                 }
2172
2173                 This->listener = (IDirectSound3DListenerImpl*)HeapAlloc(
2174                         GetProcessHeap(), 0, sizeof(*(This->listener)));
2175                 This->listener->ref = 1;
2176                 ICOM_VTBL(This->listener) = &ds3dlvt;
2177                 *ppobj = (LPVOID)This->listener;
2178                 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)*ppobj); 
2179
2180                 This->listener->dsb = NULL; 
2181
2182                 This->listener->ds3dl.dwSize = sizeof(DS3DLISTENER);
2183                 This->listener->ds3dl.vPosition.u1.x = 0.0;
2184                 This->listener->ds3dl.vPosition.u2.y = 0.0;
2185                 This->listener->ds3dl.vPosition.u3.z = 0.0;
2186                 This->listener->ds3dl.vVelocity.u1.x = 0.0;
2187                 This->listener->ds3dl.vVelocity.u2.y = 0.0;
2188                 This->listener->ds3dl.vVelocity.u3.z = 0.0;
2189                 This->listener->ds3dl.vOrientFront.u1.x = 0.0;
2190                 This->listener->ds3dl.vOrientFront.u2.y = 0.0;
2191                 This->listener->ds3dl.vOrientFront.u3.z = 1.0;
2192                 This->listener->ds3dl.vOrientTop.u1.x = 0.0;
2193                 This->listener->ds3dl.vOrientTop.u2.y = 1.0;
2194                 This->listener->ds3dl.vOrientTop.u3.z = 0.0;
2195                 This->listener->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
2196                 This->listener->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
2197                 This->listener->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
2198
2199                 InitializeCriticalSection(&This->listener->lock);
2200
2201                 return DS_OK;
2202         }
2203
2204         FIXME("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
2205         return E_FAIL;
2206 }
2207
2208 static HRESULT WINAPI IDirectSoundImpl_Compact(
2209         LPDIRECTSOUND iface)
2210 {
2211         ICOM_THIS(IDirectSoundImpl,iface);
2212         TRACE("(%p)\n", This);
2213         return DS_OK;
2214 }
2215
2216 static HRESULT WINAPI IDirectSoundImpl_GetSpeakerConfig(
2217         LPDIRECTSOUND iface,
2218         LPDWORD lpdwSpeakerConfig)
2219 {
2220         ICOM_THIS(IDirectSoundImpl,iface);
2221         TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
2222         *lpdwSpeakerConfig = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
2223         return DS_OK;
2224 }
2225
2226 static HRESULT WINAPI IDirectSoundImpl_Initialize(
2227         LPDIRECTSOUND iface,
2228         LPCGUID lpcGuid)
2229 {
2230         ICOM_THIS(IDirectSoundImpl,iface);
2231         TRACE("(%p, %p)\n", This, lpcGuid);
2232         return DS_OK;
2233 }
2234
2235 static ICOM_VTABLE(IDirectSound) dsvt = 
2236 {
2237         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2238         IDirectSoundImpl_QueryInterface,
2239         IDirectSoundImpl_AddRef,
2240         IDirectSoundImpl_Release,
2241         IDirectSoundImpl_CreateSoundBuffer,
2242         IDirectSoundImpl_GetCaps,
2243         IDirectSoundImpl_DuplicateSoundBuffer,
2244         IDirectSoundImpl_SetCooperativeLevel,
2245         IDirectSoundImpl_Compact,
2246         IDirectSoundImpl_GetSpeakerConfig,
2247         IDirectSoundImpl_SetSpeakerConfig,
2248         IDirectSoundImpl_Initialize
2249 };
2250
2251
2252 static void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len)
2253 {
2254         int                     i;
2255         DWORD                   offset;
2256         LPDSBPOSITIONNOTIFY     event;
2257
2258         if (dsb->nrofnotifies == 0)
2259                 return;
2260
2261         TRACE("(%p) buflen = %ld, playpos = %ld, len = %d\n",
2262                 dsb, dsb->buflen, dsb->playpos, len);
2263         for (i = 0; i < dsb->nrofnotifies ; i++) {
2264                 event = dsb->notifies + i;
2265                 offset = event->dwOffset;
2266                 TRACE("checking %d, position %ld, event = %d\n",
2267                         i, offset, event->hEventNotify);
2268                 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
2269                 /* OK. [Inside DirectX, p274] */
2270                 /*  */
2271                 /* This also means we can't sort the entries by offset, */
2272                 /* because DSBPN_OFFSETSTOP == -1 */
2273                 if (offset == DSBPN_OFFSETSTOP) {
2274                         if (dsb->state == STATE_STOPPED) {
2275                                 SetEvent(event->hEventNotify);
2276                                 TRACE("signalled event %d (%d)\n", event->hEventNotify, i);
2277                                 return;
2278                         } else
2279                                 return;
2280                 }
2281                 if ((dsb->playpos + len) >= dsb->buflen) {
2282                         if ((offset < ((dsb->playpos + len) % dsb->buflen)) ||
2283                             (offset >= dsb->playpos)) {
2284                                 TRACE("signalled event %d (%d)\n", event->hEventNotify, i);
2285                                 SetEvent(event->hEventNotify);
2286                         }
2287                 } else {
2288                         if ((offset >= dsb->playpos) && (offset < (dsb->playpos + len))) {
2289                                 TRACE("signalled event %d (%d)\n", event->hEventNotify, i);
2290                                 SetEvent(event->hEventNotify);
2291                         }
2292                 }
2293         }
2294 }
2295
2296 /* WAV format info can be found at: */
2297 /* */
2298 /*      http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
2299 /*      ftp://ftp.cwi.nl/pub/audio/RIFF-format */
2300 /* */
2301 /* Import points to remember: */
2302 /* */
2303 /*      8-bit WAV is unsigned */
2304 /*      16-bit WAV is signed */
2305
2306 static inline INT16 cvtU8toS16(BYTE byte)
2307 {
2308         INT16   s = (byte - 128) << 8;
2309
2310         return s;
2311 }
2312
2313 static inline BYTE cvtS16toU8(INT16 word)
2314 {
2315         BYTE    b = (word + 32768) >> 8;
2316         
2317         return b;
2318 }
2319
2320
2321 /* We should be able to optimize these two inline functions */
2322 /* so that we aren't doing 8->16->8 conversions when it is */
2323 /* not necessary. But this is still a WIP. Optimize later. */
2324 static inline void get_fields(const IDirectSoundBufferImpl *dsb, BYTE *buf, INT *fl, INT *fr)
2325 {
2326         INT16   *bufs = (INT16 *) buf;
2327
2328         /* TRACE("(%p)", buf); */
2329         if ((dsb->wfx.wBitsPerSample == 8) && dsb->wfx.nChannels == 2) {
2330                 *fl = cvtU8toS16(*buf);
2331                 *fr = cvtU8toS16(*(buf + 1));
2332                 return;
2333         }
2334
2335         if ((dsb->wfx.wBitsPerSample == 16) && dsb->wfx.nChannels == 2) {
2336                 *fl = *bufs;
2337                 *fr = *(bufs + 1);
2338                 return;
2339         }
2340
2341         if ((dsb->wfx.wBitsPerSample == 8) && dsb->wfx.nChannels == 1) {
2342                 *fl = cvtU8toS16(*buf);
2343                 *fr = *fl;
2344                 return;
2345         }
2346
2347         if ((dsb->wfx.wBitsPerSample == 16) && dsb->wfx.nChannels == 1) {
2348                 *fl = *bufs;
2349                 *fr = *bufs;
2350                 return;
2351         }
2352
2353         FIXME("get_fields found an unsupported configuration\n");
2354         return;
2355 }
2356
2357 static inline void set_fields(BYTE *buf, INT fl, INT fr)
2358 {
2359         INT16 *bufs = (INT16 *) buf;
2360
2361         if ((primarybuf->wfx.wBitsPerSample == 8) && (primarybuf->wfx.nChannels == 2)) {
2362                 *buf = cvtS16toU8(fl);
2363                 *(buf + 1) = cvtS16toU8(fr);
2364                 return;
2365         }
2366
2367         if ((primarybuf->wfx.wBitsPerSample == 16) && (primarybuf->wfx.nChannels == 2)) {
2368                 *bufs = fl;
2369                 *(bufs + 1) = fr;
2370                 return;
2371         }
2372
2373         if ((primarybuf->wfx.wBitsPerSample == 8) && (primarybuf->wfx.nChannels == 1)) {
2374                 *buf = cvtS16toU8((fl + fr) >> 1);
2375                 return;
2376         }
2377
2378         if ((primarybuf->wfx.wBitsPerSample == 16) && (primarybuf->wfx.nChannels == 1)) {
2379                 *bufs = (fl + fr) >> 1;
2380                 return;
2381         }
2382         FIXME("set_fields found an unsupported configuration\n");
2383         return;
2384 }
2385
2386 /* Now with PerfectPitch (tm) technology */
2387 static INT DSOUND_MixerNorm(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
2388 {
2389         INT     i, size, ipos, ilen, fieldL, fieldR;
2390         BYTE    *ibp, *obp;
2391         INT     iAdvance = dsb->wfx.nBlockAlign;
2392         INT     oAdvance = primarybuf->wfx.nBlockAlign;
2393
2394         ibp = dsb->buffer + dsb->mixpos;
2395         obp = buf;
2396
2397         TRACE("(%p, %p, %p), mixpos=%ld\n", dsb, ibp, obp, dsb->mixpos);
2398         /* Check for the best case */
2399         if ((dsb->freq == primarybuf->wfx.nSamplesPerSec) &&
2400             (dsb->wfx.wBitsPerSample == primarybuf->wfx.wBitsPerSample) &&
2401             (dsb->wfx.nChannels == primarybuf->wfx.nChannels)) {
2402                 DWORD bytesleft = dsb->buflen - dsb->mixpos;
2403                 TRACE("(%p) Best case\n", dsb);
2404                 if (len <= bytesleft )
2405                         memcpy(obp, ibp, len);
2406                 else { /* wrap */
2407                         memcpy(obp, ibp, bytesleft );
2408                         memcpy(obp + bytesleft, dsb->buffer, len - bytesleft);
2409                 }
2410                 return len;
2411         }
2412         
2413         /* Check for same sample rate */
2414         if (dsb->freq == primarybuf->wfx.nSamplesPerSec) {
2415                 TRACE("(%p) Same sample rate %ld = primary %ld\n", dsb,
2416                         dsb->freq, primarybuf->wfx.nSamplesPerSec);
2417                 ilen = 0;
2418                 for (i = 0; i < len; i += oAdvance) {
2419                         get_fields(dsb, ibp, &fieldL, &fieldR);
2420                         ibp += iAdvance;
2421                         ilen += iAdvance;
2422                         set_fields(obp, fieldL, fieldR);
2423                         obp += oAdvance;
2424                         if (ibp >= (BYTE *)(dsb->buffer + dsb->buflen))
2425                                 ibp = dsb->buffer;      /* wrap */
2426                 }
2427                 return (ilen);  
2428         }
2429
2430         /* Mix in different sample rates */
2431         /* */
2432         /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
2433         /* Patent Pending :-] */
2434
2435         TRACE("(%p) Adjusting frequency: %ld -> %ld\n",
2436                 dsb, dsb->freq, primarybuf->wfx.nSamplesPerSec);
2437
2438         size = len / oAdvance;
2439         ilen = ((size * dsb->freqAdjust) >> DSOUND_FREQSHIFT) * iAdvance;
2440         for (i = 0; i < size; i++) {
2441
2442                 ipos = (((i * dsb->freqAdjust) >> DSOUND_FREQSHIFT) * iAdvance) + dsb->mixpos;
2443
2444                 if (ipos >= dsb->buflen)
2445                         ipos %= dsb->buflen;    /* wrap */
2446
2447                 get_fields(dsb, (dsb->buffer + ipos), &fieldL, &fieldR);
2448                 set_fields(obp, fieldL, fieldR);
2449                 obp += oAdvance;
2450         }
2451         return ilen;
2452 }
2453
2454 static void DSOUND_MixerVol(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
2455 {
2456         INT     i, inc = primarybuf->wfx.wBitsPerSample >> 3;
2457         BYTE    *bpc = buf;
2458         INT16   *bps = (INT16 *) buf;
2459         
2460         TRACE("(%p) left = %lx, right = %lx\n", dsb,
2461                 dsb->volpan.dwTotalLeftAmpFactor, dsb->volpan.dwTotalRightAmpFactor);
2462         if ((!(dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || (dsb->volpan.lPan == 0)) &&
2463             (!(dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) || (dsb->volpan.lVolume == 0)) &&
2464             !(dsb->dsbd.dwFlags & DSBCAPS_CTRL3D))
2465                 return;         /* Nothing to do */
2466
2467         /* If we end up with some bozo coder using panning or 3D sound */
2468         /* with a mono primary buffer, it could sound very weird using */
2469         /* this method. Oh well, tough patooties. */
2470
2471         for (i = 0; i < len; i += inc) {
2472                 INT     val;
2473
2474                 switch (inc) {
2475
2476                 case 1:
2477                         /* 8-bit WAV is unsigned, but we need to operate */
2478                         /* on signed data for this to work properly */
2479                         val = *bpc - 128;
2480                         val = ((val * (i & inc ? dsb->volpan.dwTotalRightAmpFactor : dsb->volpan.dwTotalLeftAmpFactor)) >> 16);
2481                         *bpc = val + 128;
2482                         bpc++;
2483                         break;
2484                 case 2:
2485                         /* 16-bit WAV is signed -- much better */
2486                         val = *bps;
2487                         val = ((val * ((i & inc) ? dsb->volpan.dwTotalRightAmpFactor : dsb->volpan.dwTotalLeftAmpFactor)) >> 16);
2488                         *bps = val;
2489                         bps++;
2490                         break;
2491                 default:
2492                         /* Very ugly! */
2493                         FIXME("MixerVol had a nasty error\n");
2494                 }
2495         }               
2496 }
2497
2498 #ifdef USE_DSOUND3D
2499 static void DSOUND_Mixer3D(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
2500 {
2501         BYTE    *ibp, *obp;
2502         DWORD   buflen, mixpos;
2503
2504         buflen = dsb->ds3db->buflen;
2505         mixpos = (dsb->mixpos * primarybuf->wfx.nBlockAlign) / dsb->wfx.nBlockAlign;
2506         ibp = dsb->ds3db->buffer + mixpos;
2507         obp = buf;
2508
2509         if (mixpos > buflen) {
2510                 FIXME("Major breakage");
2511                 return;
2512         }
2513
2514         if (len <= (mixpos + buflen))
2515                 memcpy(obp, ibp, len);
2516         else { /* wrap */
2517                 memcpy(obp, ibp, buflen - mixpos);
2518                 memcpy(obp + (buflen - mixpos),
2519                     dsb->buffer,
2520                     len - (buflen - mixpos));
2521         }
2522         return;
2523 }
2524 #endif
2525
2526 static void *tmp_buffer;
2527 static size_t tmp_buffer_len = 0;
2528
2529 static void *DSOUND_tmpbuffer(size_t len)
2530 {
2531   if (len>tmp_buffer_len) {
2532     void *new_buffer = realloc(tmp_buffer, len);
2533     if (new_buffer) {
2534       tmp_buffer = new_buffer;
2535       tmp_buffer_len = len;
2536     }
2537     return new_buffer;
2538   }
2539   return tmp_buffer;
2540 }
2541
2542 static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD fraglen)
2543 {
2544         INT     i, len, ilen, temp, field;
2545         INT     advance = primarybuf->wfx.wBitsPerSample >> 3;
2546         BYTE    *buf, *ibuf, *obuf;
2547         INT16   *ibufs, *obufs;
2548
2549         len = fraglen;
2550         if (!(dsb->playflags & DSBPLAY_LOOPING)) {
2551                 temp = MulDiv(primarybuf->wfx.nAvgBytesPerSec, dsb->buflen,
2552                         dsb->nAvgBytesPerSec) -
2553                        MulDiv(primarybuf->wfx.nAvgBytesPerSec, dsb->mixpos,
2554                         dsb->nAvgBytesPerSec);
2555                 len = (len > temp) ? temp : len;
2556         }
2557         len &= ~3;                              /* 4 byte alignment */
2558
2559         if (len == 0) {
2560                 /* This should only happen if we aren't looping and temp < 4 */
2561
2562                 /* We skip the remainder, so check for possible events */
2563                 DSOUND_CheckEvent(dsb, dsb->buflen - dsb->mixpos);
2564                 /* Stop */
2565                 dsb->state = STATE_STOPPED;
2566                 dsb->playpos = 0;
2567                 dsb->mixpos = 0;
2568                 dsb->leadin = FALSE;
2569                 /* Check for DSBPN_OFFSETSTOP */
2570                 DSOUND_CheckEvent(dsb, 0);
2571                 return 0;
2572         }
2573
2574         /* Been seeing segfaults in malloc() for some reason... */
2575         TRACE("allocating buffer (size = %d)\n", len);
2576         if ((buf = ibuf = (BYTE *) DSOUND_tmpbuffer(len)) == NULL)
2577                 return 0;
2578
2579         TRACE("MixInBuffer (%p) len = %d, dest = %ld\n", dsb, len, writepos);
2580
2581         ilen = DSOUND_MixerNorm(dsb, ibuf, len);
2582         if ((dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
2583             (dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME))
2584                 DSOUND_MixerVol(dsb, ibuf, len);
2585
2586         obuf = primarybuf->buffer + writepos;
2587         for (i = 0; i < len; i += advance) {
2588                 obufs = (INT16 *) obuf;
2589                 ibufs = (INT16 *) ibuf;
2590                 if (primarybuf->wfx.wBitsPerSample == 8) {
2591                         /* 8-bit WAV is unsigned */
2592                         field = (*ibuf - 128);
2593                         field += (*obuf - 128);
2594                         field = field > 127 ? 127 : field;
2595                         field = field < -128 ? -128 : field;
2596                         *obuf = field + 128;
2597                 } else {
2598                         /* 16-bit WAV is signed */
2599                         field = *ibufs;
2600                         field += *obufs;
2601                         field = field > 32767 ? 32767 : field;
2602                         field = field < -32768 ? -32768 : field;
2603                         *obufs = field;
2604                 }
2605                 ibuf += advance;
2606                 obuf += advance;
2607                 if (obuf >= (BYTE *)(primarybuf->buffer + primarybuf->buflen))
2608                         obuf = primarybuf->buffer;
2609         }
2610         /* free(buf); */
2611
2612         if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY)
2613                 DSOUND_CheckEvent(dsb, ilen);
2614
2615         if (dsb->leadin && (dsb->startpos > dsb->mixpos) && (dsb->startpos <= dsb->mixpos + ilen)) {
2616                 /* HACK... leadin should be reset when the PLAY position reaches the startpos,
2617                  * not the MIX position... but if the sound buffer is bigger than our prebuffering
2618                  * (which must be the case for the streaming buffers that need this hack anyway)
2619                  * plus DS_HEL_MARGIN or equivalent, then this ought to work anyway. */
2620                 dsb->leadin = FALSE;
2621         }
2622
2623         dsb->mixpos += ilen;
2624         
2625         if (dsb->mixpos >= dsb->buflen) {
2626                 if (!(dsb->playflags & DSBPLAY_LOOPING)) {
2627                         dsb->state = STATE_STOPPED;
2628                         dsb->playpos = 0;
2629                         dsb->mixpos = 0;
2630                         dsb->leadin = FALSE;
2631                         DSOUND_CheckEvent(dsb, 0);              /* For DSBPN_OFFSETSTOP */
2632                 } else {
2633                         /* wrap */
2634                         while (dsb->mixpos >= dsb->buflen)
2635                                 dsb->mixpos -= dsb->buflen;
2636                         if (dsb->leadin && (dsb->startpos <= dsb->mixpos))
2637                                 dsb->leadin = FALSE; /* HACK: see above */
2638                 }
2639         }
2640
2641         return len;
2642 }
2643
2644 static DWORD WINAPI DSOUND_MixPrimary(DWORD writepos, DWORD fraglen, BOOL starting)
2645 {
2646         INT                     i, len, maxlen = 0;
2647         IDirectSoundBufferImpl  *dsb;
2648
2649         TRACE("(%ld,%ld,%d)\n", writepos, fraglen, starting);
2650         for (i = dsound->nrofbuffers - 1; i >= 0; i--) {
2651                 dsb = dsound->buffers[i];
2652
2653                 if (!dsb || !(ICOM_VTBL(dsb)))
2654                         continue;
2655                 if (dsb->buflen && dsb->state && !(starting && (dsb->state != STATE_STARTING))) {
2656                         TRACE("Checking %p\n", dsb);
2657                         EnterCriticalSection(&(dsb->lock));
2658                         if (dsb->state == STATE_STOPPING) {
2659                                 /* FIXME: perhaps attempt to remove the buffer from the prebuffer */
2660                                 dsb->state = STATE_STOPPED;
2661                         } else {
2662                                 len = DSOUND_MixInBuffer(dsb, writepos, fraglen);
2663                                 maxlen = len > maxlen ? len : maxlen;
2664                         }
2665                         LeaveCriticalSection(&(dsb->lock));
2666                 }
2667         }
2668         
2669         return maxlen;
2670 }
2671
2672 static void WINAPI DSOUND_MarkPlaying(void)
2673 {
2674         INT                     i;
2675         IDirectSoundBufferImpl  *dsb;
2676
2677         for (i = dsound->nrofbuffers - 1; i >= 0; i--) {
2678                 dsb = dsound->buffers[i];
2679
2680                 if (!dsb || !(ICOM_VTBL(dsb)))
2681                         continue;
2682                 if (dsb->buflen && (dsb->state == STATE_STARTING))
2683                         dsb->state = STATE_PLAYING;
2684         }
2685 }
2686
2687 static void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2)
2688 {
2689         DWORD len;
2690         int nfiller;
2691         BOOL forced;
2692
2693         if (!dsound || !primarybuf) {
2694                 ERR("dsound died without killing us?\n");
2695                 timeKillEvent(timerID);
2696                 timeEndPeriod(DS_TIME_RES);
2697                 return;
2698         }
2699
2700         EnterCriticalSection(&(dsound->lock));
2701
2702         if (!primarybuf || !primarybuf->ref) {
2703                 /* seems the primary buffer is currently being released */
2704                 LeaveCriticalSection(&(dsound->lock));
2705                 return;
2706         }
2707
2708         /* the sound of silence */
2709         nfiller = primarybuf->wfx.wBitsPerSample == 8 ? 128 : 0;
2710
2711         /* whether the primary is forced to play even without secondary buffers */
2712         forced = ((primarybuf->state == STATE_PLAYING) || (primarybuf->state == STATE_STARTING));
2713
2714         if (primarybuf->hwbuf) {
2715                 if (dsound->priolevel != DSSCL_WRITEPRIMARY) {
2716                         BOOL paused = ((primarybuf->state == STATE_STOPPED) || (primarybuf->state == STATE_STARTING));
2717                         DWORD playpos, writepos, inq, maxq, mixq, frag;
2718                         IDsDriverBuffer_GetPosition(primarybuf->hwbuf, &playpos, &writepos);
2719                         /* Well, we *could* do Just-In-Time mixing using the writepos,
2720                          * but that's a little bit ambitious and unnecessary... */
2721                         /* rather add our safety margin to the writepos, if we're playing */
2722                         if (!paused) {
2723                                 writepos += primarybuf->writelead;
2724                                 while (writepos >= primarybuf->buflen)
2725                                         writepos -= primarybuf->buflen;
2726                         } else writepos = playpos;
2727                         TRACE("primary playpos=%ld, writepos=%ld, clrpos=%ld, mixpos=%ld\n",
2728                               playpos,writepos,primarybuf->playpos,primarybuf->mixpos);
2729                         /* wipe out just-played sound data */
2730                         if (playpos < primarybuf->playpos) {
2731                                 memset(primarybuf->buffer + primarybuf->playpos, nfiller, primarybuf->buflen - primarybuf->playpos);
2732                                 memset(primarybuf->buffer, nfiller, playpos);
2733                         } else {
2734                                 memset(primarybuf->buffer + primarybuf->playpos, nfiller, playpos - primarybuf->playpos);
2735                         }
2736                         primarybuf->playpos = playpos;
2737
2738                         /* check how much prebuffering is left */
2739                         inq = primarybuf->mixpos;
2740                         if (inq < writepos)
2741                                 inq += primarybuf->buflen;
2742                         inq -= writepos;
2743
2744                         /* find the maximum we can prebuffer */
2745                         if (!paused) {
2746                                 maxq = playpos;
2747                                 if (maxq < writepos)
2748                                         maxq += primarybuf->buflen;
2749                                 maxq -= writepos;
2750                         } else maxq = primarybuf->buflen;
2751
2752                         /* clip maxq to DS_HAL_QUEUE */
2753                         frag = DS_HAL_QUEUE * dsound->fraglen;
2754                         if (maxq > frag) maxq = frag;
2755
2756                         EnterCriticalSection(&(primarybuf->lock));
2757
2758                         /* check for consistency */
2759                         if (inq > maxq) {
2760                                 /* the playback position must have passed our last
2761                                  * mixed position, i.e. it's an underrun, or we have
2762                                  * nothing more to play */
2763                                 inq = 0;
2764                                 /* stop the playback now, to allow buffers to refill */
2765                                 IDsDriverBuffer_Stop(primarybuf->hwbuf);
2766                                 if (primarybuf->state == STATE_PLAYING) {
2767                                         primarybuf->state = STATE_STARTING;
2768                                 }
2769                                 else if (primarybuf->state == STATE_STOPPING) {
2770                                         primarybuf->state = STATE_STOPPED;
2771                                 }
2772                                 else {
2773                                         /* how can we have an underrun if we aren't playing? */
2774                                         ERR("unexpected primary state (%ld)\n", primarybuf->state);
2775                                 }
2776                                 /* the Stop is supposed to reset play position to beginning of buffer */
2777                                 /* unfortunately, OSS is not able to do so, so get current pointer */
2778                                 IDsDriverBuffer_GetPosition(primarybuf->hwbuf, &playpos, NULL);
2779                                 writepos = playpos;
2780                                 primarybuf->playpos = playpos;
2781                                 primarybuf->mixpos = playpos;
2782                                 inq = 0;
2783                                 maxq = primarybuf->buflen;
2784                                 if (maxq > frag) maxq = frag;
2785                                 memset(primarybuf->buffer, nfiller, primarybuf->buflen);
2786                                 paused = TRUE;
2787                         }
2788
2789                         /* see if some new buffers have been started that we want to merge into our prebuffer;
2790                          * this should minimize latency even when we have a large prebuffer */
2791                         if (!paused) {
2792                                 if (primarybuf->mixpos < writepos) {
2793                                         /* mix to end of buffer */
2794                                         len = DSOUND_MixPrimary(writepos, primarybuf->buflen - writepos, TRUE);
2795                                         if ((len + writepos) < primarybuf->buflen)
2796                                                 goto addmix_complete;
2797                                         /* mix from beginning of buffer */
2798                                         if (primarybuf->mixpos)
2799                                                 len = DSOUND_MixPrimary(0, primarybuf->mixpos, TRUE);
2800                                 } else {
2801                                         /* mix middle of buffer */
2802                                         len = DSOUND_MixPrimary(writepos, primarybuf->mixpos - writepos, TRUE);
2803                                 }
2804                         }
2805                 addmix_complete:
2806                         DSOUND_MarkPlaying();
2807
2808                         mixq = maxq - inq;
2809                         TRACE("queued %ld, max %ld, mixing %ld, paused %d\n", inq, maxq, mixq, paused);
2810                         /* it's too inefficient to mix less than a fragment at a time */
2811                         if (mixq >= dsound->fraglen) {
2812
2813 #define FRAG_MIXER \
2814         if (frag > mixq) frag = mixq; \
2815         len = DSOUND_MixPrimary(primarybuf->mixpos, frag, FALSE); \
2816         if (forced) len = frag; \
2817         primarybuf->mixpos += len; \
2818         mixq -= len; inq += len
2819
2820                                 if ((playpos < writepos) || (paused && (playpos == writepos))) {
2821                                         if (primarybuf->mixpos) {
2822                                                 /* mix to end of buffer */
2823                                                 frag = primarybuf->buflen - primarybuf->mixpos;
2824                                                 FRAG_MIXER;
2825                                                 if (primarybuf->mixpos < primarybuf->buflen)
2826                                                         goto mix_complete;
2827                                                 primarybuf->mixpos = 0;
2828                                         }
2829                                         if (mixq >= dsound->fraglen) {
2830                                                 /* mix from beginning of buffer */
2831                                                 frag = playpos;
2832                                                 if ((!frag) && paused) frag = primarybuf->buflen;
2833                                                 FRAG_MIXER;
2834                                         }
2835                                 }
2836                                 else if (playpos > writepos) {
2837                                         /* mix middle of buffer */
2838                                         frag = playpos - primarybuf->mixpos;
2839                                         FRAG_MIXER;
2840                                 }
2841                                 else {
2842                                         /* this should preferably not happen... */
2843                                         ERR("mixer malfunction (ambiguous writepos)!\n");
2844                                 }
2845 #undef FRAG_MIXER
2846                         }
2847                 mix_complete:
2848                         if (inq) {
2849                                 /* buffers have been filled, restart playback */
2850                                 if (primarybuf->state == STATE_STARTING) {
2851                                         IDsDriverBuffer_Play(primarybuf->hwbuf, 0, 0, DSBPLAY_LOOPING);
2852                                         primarybuf->state = STATE_PLAYING;
2853                                 }
2854                                 else if (primarybuf->state == STATE_STOPPED) {
2855                                         /* the primarybuf is supposed to play if there's something to play
2856                                          * even if it is reported as stopped, so don't let this confuse you */
2857                                         IDsDriverBuffer_Play(primarybuf->hwbuf, 0, 0, DSBPLAY_LOOPING);
2858                                         primarybuf->state = STATE_STOPPING;
2859                                 }
2860                         }
2861                         LeaveCriticalSection(&(primarybuf->lock));
2862                 } else {
2863                         /* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */
2864                         if (primarybuf->state == STATE_STARTING) {
2865                                 IDsDriverBuffer_Play(primarybuf->hwbuf, 0, 0, DSBPLAY_LOOPING);
2866                                 primarybuf->state = STATE_PLAYING;
2867                         } 
2868                         else if (primarybuf->state == STATE_STOPPING) {
2869                                 IDsDriverBuffer_Stop(primarybuf->hwbuf);
2870                                 primarybuf->state = STATE_STOPPED;
2871                         }
2872                 }
2873         } else {
2874                 /* using waveOut stuff */
2875                 /* if no buffers are playing, we should be in pause mode now */
2876                 DWORD writepos;
2877                 /* clean out completed fragments */
2878                 while (dsound->pwqueue && (dsound->pwave[dsound->pwplay]->dwFlags & WHDR_DONE)) {
2879                         if (dsound->priolevel != DSSCL_WRITEPRIMARY) {
2880                                 DWORD pos = dsound->pwplay * dsound->fraglen;
2881                                 TRACE("done playing primary pos=%ld\n",pos);
2882                                 memset(primarybuf->buffer + pos, nfiller, dsound->fraglen);
2883                         }
2884                         dsound->pwplay++;
2885                         if (dsound->pwplay >= DS_HEL_FRAGS) dsound->pwplay = 0;
2886                         dsound->pwqueue--;
2887                 }
2888                 primarybuf->playpos = dsound->pwplay * dsound->fraglen;
2889                 TRACE("primary playpos=%ld, mixpos=%ld\n",primarybuf->playpos,primarybuf->mixpos);
2890                 EnterCriticalSection(&(primarybuf->lock));
2891                 if (!dsound->pwqueue) {
2892                         /* this is either an underrun or we have nothing more to play...
2893                          * since playback has already stopped now, we can enter pause mode,
2894                          * in order to allow buffers to refill */
2895                         if (primarybuf->state == STATE_PLAYING) {
2896                                 waveOutPause(dsound->hwo);
2897                                 primarybuf->state = STATE_STARTING;
2898                         }
2899                         else if (primarybuf->state == STATE_STOPPING) {
2900                                 waveOutPause(dsound->hwo);
2901                                 primarybuf->state = STATE_STOPPED;
2902                         }
2903                 }
2904
2905                 /* find next write position, plus some extra margin */
2906                 writepos = primarybuf->playpos + DS_HEL_MARGIN * dsound->fraglen;
2907                 while (writepos >= primarybuf->buflen) writepos -= primarybuf->buflen;
2908
2909                 /* see if some new buffers have been started that we want to merge into our prebuffer;
2910                  * this should minimize latency even when we have a large prebuffer */
2911                 if (dsound->priolevel != DSSCL_WRITEPRIMARY) {
2912                         if ((primarybuf->state == STATE_PLAYING) || (primarybuf->state == STATE_STOPPING)) {
2913                                 while (writepos != primarybuf->mixpos) {
2914                                         len = DSOUND_MixPrimary(writepos, dsound->fraglen, TRUE);
2915                                         if (!len) break;
2916                                         writepos += dsound->fraglen;
2917                                         if (writepos >= primarybuf->buflen)
2918                                                 writepos -= primarybuf->buflen;
2919                                 }
2920                         }
2921                         DSOUND_MarkPlaying();
2922                 }
2923
2924                 /* we want at least DS_HEL_QUEUE fragments in the prebuffer outqueue;
2925                  * mix a bunch of fragments now as necessary */
2926                 while (dsound->pwqueue < DS_HEL_QUEUE) {
2927                         if (dsound->priolevel != DSSCL_WRITEPRIMARY) {
2928                                 len = DSOUND_MixPrimary(primarybuf->mixpos, dsound->fraglen, FALSE);
2929                         } else len=0;
2930                         if (forced) len = dsound->fraglen;
2931                         /* if we have nothing to play, don't bother to */
2932                         if (!len) break;
2933                         if (len < dsound->fraglen) {
2934                                 TRACE("len=%ld is less than fraglen=%ld\n",len,dsound->fraglen);
2935                         }
2936                         /* ok, we have something to play */
2937                         /* advance mix positions */
2938                         primarybuf->mixpos += dsound->fraglen;
2939                         if (primarybuf->mixpos >= primarybuf->buflen)
2940                                 primarybuf->mixpos -= primarybuf->buflen;
2941                         /* output it */
2942                         waveOutWrite(dsound->hwo, dsound->pwave[dsound->pwwrite], sizeof(WAVEHDR));
2943                         dsound->pwwrite++;
2944                         if (dsound->pwwrite >= DS_HEL_FRAGS) dsound->pwwrite = 0;
2945                         dsound->pwqueue++;
2946                 }
2947                 if (dsound->pwqueue) {
2948                         /* buffers have been filled, restart playback */
2949                         if (primarybuf->state == STATE_STARTING) {
2950                                 waveOutRestart(dsound->hwo);
2951                                 primarybuf->state = STATE_PLAYING;
2952                         }
2953                         else if (primarybuf->state == STATE_STOPPED) {
2954                                 /* the primarybuf is supposed to play if there's something to play
2955                                  * even if it is reported as stopped, so don't let this confuse you */
2956                                 waveOutRestart(dsound->hwo);
2957                                 primarybuf->state = STATE_STOPPING;
2958                         }
2959                 }
2960                 LeaveCriticalSection(&(primarybuf->lock));
2961         }
2962         LeaveCriticalSection(&(dsound->lock));
2963 }
2964
2965 /*******************************************************************************
2966  *              DirectSoundCreate
2967  */
2968 HRESULT WINAPI DirectSoundCreate(REFGUID lpGUID,LPDIRECTSOUND *ppDS,IUnknown *pUnkOuter )
2969 {
2970         IDirectSoundImpl** ippDS=(IDirectSoundImpl**)ppDS;
2971         PIDSDRIVER drv = NULL;
2972         WAVEOUTCAPSA wcaps;
2973         unsigned wod, wodn;
2974         HRESULT err = DS_OK;
2975
2976         if (lpGUID)
2977                 TRACE("(%p,%p,%p)\n",lpGUID,ippDS,pUnkOuter);
2978         else
2979                 TRACE("DirectSoundCreate (%p)\n", ippDS);
2980
2981         if (ippDS == NULL)
2982                 return DSERR_INVALIDPARAM;
2983
2984         if (primarybuf) {
2985                 IDirectSound_AddRef((LPDIRECTSOUND)dsound);
2986                 *ippDS = dsound;
2987                 return DS_OK;
2988         }
2989
2990         /* Enumerate WINMM audio devices and find the one we want */
2991         wodn = waveOutGetNumDevs();
2992         if (!wodn) return DSERR_NODRIVER;
2993
2994         /* FIXME: How do we find the GUID of an audio device? */
2995         /* Well, just use the first available device for now... */
2996         wod = 0;
2997         /* Get output device caps */
2998         waveOutGetDevCapsA(wod, &wcaps, sizeof(wcaps));
2999         /* 0x810 is a "Wine extension" to get the DSound interface */
3000         waveOutMessage(wod, 0x810, (DWORD)&drv, 0);
3001
3002         /* Allocate memory */
3003         *ippDS = (IDirectSoundImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundImpl));
3004         if (*ippDS == NULL)
3005                 return DSERR_OUTOFMEMORY;
3006
3007         ICOM_VTBL(*ippDS)       = &dsvt;
3008         (*ippDS)->ref           = 1;
3009
3010         (*ippDS)->driver        = drv;
3011         (*ippDS)->fraglen       = 0;
3012         (*ippDS)->priolevel     = DSSCL_NORMAL; 
3013         (*ippDS)->nrofbuffers   = 0;
3014         (*ippDS)->buffers       = NULL;
3015         (*ippDS)->primary       = NULL; 
3016         (*ippDS)->listener      = NULL; 
3017
3018         /* Get driver description */
3019         if (drv) {
3020                 IDsDriver_GetDriverDesc(drv,&((*ippDS)->drvdesc));
3021         } else {
3022                 /* if no DirectSound interface available, use WINMM API instead */
3023                 (*ippDS)->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT;
3024                 (*ippDS)->drvdesc.dnDevNode = wod; /* FIXME? */
3025         }
3026
3027         /* Set default wave format (may need it for waveOutOpen) */
3028         (*ippDS)->wfx.wFormatTag        = WAVE_FORMAT_PCM;
3029         (*ippDS)->wfx.nChannels         = 2;
3030         (*ippDS)->wfx.nSamplesPerSec    = 22050;
3031         (*ippDS)->wfx.nAvgBytesPerSec   = 44100;
3032         (*ippDS)->wfx.nBlockAlign       = 2;
3033         (*ippDS)->wfx.wBitsPerSample    = 8;
3034
3035         /* If the driver requests being opened through MMSYSTEM
3036          * (which is recommended by the DDK), it is supposed to happen
3037          * before the DirectSound interface is opened */
3038         if ((*ippDS)->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) {
3039                 /* FIXME: is this right? */
3040                 err = mmErr(waveOutOpen(&((*ippDS)->hwo), (*ippDS)->drvdesc.dnDevNode, &((*ippDS)->wfx),
3041                                         0, 0, CALLBACK_NULL | WAVE_DIRECTSOUND));
3042         }
3043
3044         if (drv && (err == DS_OK))
3045                 err = IDsDriver_Open(drv);
3046
3047         /* FIXME: do we want to handle a temporarily busy device? */
3048         if (err != DS_OK) {
3049                 HeapFree(GetProcessHeap(),0,*ippDS);
3050                 *ippDS = NULL;
3051                 return err;
3052         }
3053
3054         /* the driver is now open, so it's now allowed to call GetCaps */
3055         if (drv) {
3056                 IDsDriver_GetCaps(drv,&((*ippDS)->drvcaps));
3057         } else {
3058                 unsigned c;
3059
3060                 /* FIXME: look at wcaps */
3061                 (*ippDS)->drvcaps.dwFlags =
3062                         DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO;
3063                 if (DS_EMULDRIVER)
3064                     (*ippDS)->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
3065
3066                 /* Allocate memory for HEL buffer headers */
3067                 for (c=0; c<DS_HEL_FRAGS; c++) {
3068                         (*ippDS)->pwave[c] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEHDR));
3069                         if (!(*ippDS)->pwave[c]) {
3070                                 /* Argh, out of memory */
3071                                 while (c--) {
3072                                         HeapFree(GetProcessHeap(),0,(*ippDS)->pwave[c]);
3073                                         waveOutClose((*ippDS)->hwo);
3074                                         HeapFree(GetProcessHeap(),0,*ippDS);
3075                                         *ippDS = NULL;
3076                                         return DSERR_OUTOFMEMORY;
3077                                 }
3078                         }
3079                 }
3080         }
3081
3082         InitializeCriticalSection(&((*ippDS)->lock));
3083
3084         if (!dsound) {
3085                 dsound = (*ippDS);
3086                 if (primarybuf == NULL) {
3087                         DSBUFFERDESC    dsbd;
3088                         HRESULT         hr;
3089
3090                         dsbd.dwSize = sizeof(DSBUFFERDESC);
3091                         dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2;
3092                         dsbd.dwBufferBytes = 0;
3093                         dsbd.lpwfxFormat = &(dsound->wfx);
3094                         hr = IDirectSound_CreateSoundBuffer(*ppDS, &dsbd, (LPDIRECTSOUNDBUFFER*)&primarybuf, NULL);
3095                         if (hr != DS_OK)
3096                                 return hr;
3097
3098                         /* dsound->primary is NULL - don't need to Release */
3099                         dsound->primary = primarybuf;
3100                         IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)primarybuf);
3101                 }
3102                 timeBeginPeriod(DS_TIME_RES);
3103                 dsound->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, DSOUND_timer,
3104                                                (DWORD)dsound, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
3105         }
3106         return DS_OK;
3107 }
3108
3109 /***************************************************************************
3110  * DirectSoundCaptureCreate [DSOUND.6]
3111  *
3112  * Create and initialize a DirectSoundCapture interface
3113  *
3114  * RETURNS
3115  *    Success: DS_OK
3116  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
3117  *             DSERR_OUTOFMEMORY
3118  */
3119 HRESULT WINAPI DirectSoundCaptureCreate(
3120         LPCGUID lpcGUID,
3121         LPDIRECTSOUNDCAPTURE* lplpDSC,
3122         LPUNKNOWN pUnkOuter )
3123 {
3124         TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), lplpDSC, pUnkOuter);
3125
3126         if( pUnkOuter ) {
3127                 return DSERR_NOAGGREGATION;
3128         }
3129
3130         /* Default device? */
3131         if ( !lpcGUID ) {
3132                 return DSOUND_CreateDirectSoundCapture( (LPVOID*)lplpDSC );
3133         }
3134
3135         FIXME( "Unknown GUID %s\n", debugstr_guid(lpcGUID) );
3136         *lplpDSC = NULL;
3137
3138         return DSERR_OUTOFMEMORY;
3139 }
3140
3141 /***************************************************************************
3142  * DirectSoundCaptureEnumerateA [DSOUND.7]
3143  *
3144  * Enumerate all DirectSound drivers installed in the system
3145  *
3146  * RETURNS
3147  *    Success: DS_OK
3148  *    Failure: DSERR_INVALIDPARAM
3149  */
3150 HRESULT WINAPI DirectSoundCaptureEnumerateA(
3151         LPDSENUMCALLBACKA lpDSEnumCallback,
3152         LPVOID lpContext)
3153 {
3154         TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
3155
3156         if ( lpDSEnumCallback )
3157                 lpDSEnumCallback(NULL,"WINE Primary Sound Capture Driver",
3158                     "SoundCap",lpContext);
3159
3160
3161         return DS_OK;
3162 }
3163
3164 /***************************************************************************
3165  * DirectSoundCaptureEnumerateW [DSOUND.8]
3166  *
3167  * Enumerate all DirectSound drivers installed in the system
3168  *
3169  * RETURNS
3170  *    Success: DS_OK
3171  *    Failure: DSERR_INVALIDPARAM
3172  */
3173 HRESULT WINAPI DirectSoundCaptureEnumerateW(
3174         LPDSENUMCALLBACKW lpDSEnumCallback,
3175         LPVOID lpContext)
3176 {
3177         FIXME("(%p,%p):stub\n", lpDSEnumCallback, lpContext );
3178         return DS_OK;
3179
3180
3181 static HRESULT
3182 DSOUND_CreateDirectSoundCapture( LPVOID* ppobj )
3183 {
3184         *ppobj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( IDirectSoundCaptureImpl ) );
3185
3186         if ( *ppobj == NULL ) {
3187                 return DSERR_OUTOFMEMORY;
3188         }
3189
3190         {
3191                 ICOM_THIS(IDirectSoundCaptureImpl,*ppobj);
3192
3193                 This->ref = 1;
3194                 ICOM_VTBL(This) = &dscvt;
3195
3196                 InitializeCriticalSection( &This->lock );
3197         }
3198
3199         return S_OK;
3200 }
3201
3202 static HRESULT WINAPI
3203 IDirectSoundCaptureImpl_QueryInterface(
3204         LPDIRECTSOUNDCAPTURE iface,
3205         REFIID riid,
3206         LPVOID* ppobj )
3207 {
3208         ICOM_THIS(IDirectSoundCaptureImpl,iface);
3209
3210         FIXME( "(%p)->(%s,%p): stub\n", This, debugstr_guid(riid), ppobj );
3211
3212         return E_FAIL;
3213 }
3214
3215 static ULONG WINAPI
3216 IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface )
3217 {
3218         ULONG uRef;
3219         ICOM_THIS(IDirectSoundCaptureImpl,iface);
3220
3221         EnterCriticalSection( &This->lock );
3222
3223         TRACE( "(%p) was 0x%08lx\n", This, This->ref );
3224         uRef = ++(This->ref);
3225
3226         LeaveCriticalSection( &This->lock );
3227
3228         return uRef;
3229 }
3230
3231 static ULONG WINAPI
3232 IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface )
3233 {
3234         ULONG uRef;
3235         ICOM_THIS(IDirectSoundCaptureImpl,iface);
3236
3237         EnterCriticalSection( &This->lock );
3238
3239         TRACE( "(%p) was 0x%08lx\n", This, This->ref );
3240         uRef = --(This->ref);
3241
3242         LeaveCriticalSection( &This->lock );
3243
3244         if ( uRef == 0 ) {
3245                 DeleteCriticalSection( &This->lock );
3246                 HeapFree( GetProcessHeap(), 0, This );
3247         }
3248
3249         return uRef;
3250 }
3251
3252 static HRESULT WINAPI
3253 IDirectSoundCaptureImpl_CreateCaptureBuffer(
3254         LPDIRECTSOUNDCAPTURE iface,
3255         LPCDSCBUFFERDESC lpcDSCBufferDesc,
3256         LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer, 
3257         LPUNKNOWN pUnk )
3258 {
3259         HRESULT hr;
3260         ICOM_THIS(IDirectSoundCaptureImpl,iface);
3261
3262         TRACE( "(%p)->(%p,%p,%p)\n", This, lpcDSCBufferDesc, lplpDSCaptureBuffer, pUnk );
3263
3264         if ( pUnk ) {
3265                 return DSERR_INVALIDPARAM;
3266         }
3267
3268         hr = DSOUND_CreateDirectSoundCaptureBuffer( lpcDSCBufferDesc, (LPVOID*)lplpDSCaptureBuffer );
3269
3270         return hr;
3271 }
3272
3273 static HRESULT WINAPI
3274 IDirectSoundCaptureImpl_GetCaps(
3275         LPDIRECTSOUNDCAPTURE iface,
3276         LPDSCCAPS lpDSCCaps )
3277 {
3278         ICOM_THIS(IDirectSoundCaptureImpl,iface);
3279
3280         FIXME( "(%p)->(%p): stub\n", This, lpDSCCaps );
3281
3282         return DS_OK;
3283 }
3284
3285 static HRESULT WINAPI
3286 IDirectSoundCaptureImpl_Initialize(
3287         LPDIRECTSOUNDCAPTURE iface,
3288         LPCGUID lpcGUID )
3289 {
3290         ICOM_THIS(IDirectSoundCaptureImpl,iface);
3291
3292         FIXME( "(%p)->(%p): stub\n", This, lpcGUID );
3293
3294         return DS_OK;
3295 }
3296
3297
3298 static ICOM_VTABLE(IDirectSoundCapture) dscvt =
3299 {
3300         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3301         /* IUnknown methods */
3302         IDirectSoundCaptureImpl_QueryInterface,
3303         IDirectSoundCaptureImpl_AddRef,
3304         IDirectSoundCaptureImpl_Release,
3305
3306         /* IDirectSoundCapture methods */
3307         IDirectSoundCaptureImpl_CreateCaptureBuffer,
3308         IDirectSoundCaptureImpl_GetCaps,
3309         IDirectSoundCaptureImpl_Initialize 
3310 };
3311
3312 static HRESULT
3313 DSOUND_CreateDirectSoundCaptureBuffer( LPCDSCBUFFERDESC lpcDSCBufferDesc, LPVOID* ppobj )
3314 {
3315
3316         FIXME( "(%p,%p): ignoring lpcDSCBufferDesc\n", lpcDSCBufferDesc, ppobj );
3317
3318         *ppobj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( IDirectSoundCaptureBufferImpl ) );
3319
3320         if ( *ppobj == NULL ) {
3321                 return DSERR_OUTOFMEMORY;
3322         }
3323
3324         {
3325                 ICOM_THIS(IDirectSoundCaptureBufferImpl,*ppobj);
3326
3327                 This->ref = 1;
3328                 ICOM_VTBL(This) = &dscbvt;
3329
3330                 InitializeCriticalSection( &This->lock );
3331         }
3332
3333         return S_OK;
3334 }
3335
3336
3337 static HRESULT WINAPI
3338 IDirectSoundCaptureBufferImpl_QueryInterface(
3339         LPDIRECTSOUNDCAPTUREBUFFER iface,
3340         REFIID riid,
3341         LPVOID* ppobj )
3342 {
3343         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3344
3345         FIXME( "(%p)->(%s,%p): stub\n", This, debugstr_guid(riid), ppobj );
3346
3347         return E_FAIL;
3348 }
3349
3350 static ULONG WINAPI
3351 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER iface )
3352 {
3353         ULONG uRef;
3354         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3355
3356         EnterCriticalSection( &This->lock );
3357
3358         TRACE( "(%p) was 0x%08lx\n", This, This->ref );
3359         uRef = ++(This->ref);
3360
3361         LeaveCriticalSection( &This->lock );
3362
3363         return uRef;
3364 }
3365
3366 static ULONG WINAPI
3367 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER iface )
3368 {
3369         ULONG uRef;
3370         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3371
3372         EnterCriticalSection( &This->lock );
3373
3374         TRACE( "(%p) was 0x%08lx\n", This, This->ref );
3375         uRef = --(This->ref);
3376
3377         LeaveCriticalSection( &This->lock );
3378
3379         if ( uRef == 0 ) {
3380                 DeleteCriticalSection( &This->lock );
3381                 HeapFree( GetProcessHeap(), 0, This );
3382         }
3383
3384         return uRef;
3385 }
3386
3387 static HRESULT WINAPI
3388 IDirectSoundCaptureBufferImpl_GetCaps(
3389         LPDIRECTSOUNDCAPTUREBUFFER iface,
3390         LPDSCBCAPS lpDSCBCaps )
3391 {
3392         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3393
3394         FIXME( "(%p)->(%p): stub\n", This, lpDSCBCaps );
3395
3396         return DS_OK;
3397 }
3398
3399 static HRESULT WINAPI
3400 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
3401         LPDIRECTSOUNDCAPTUREBUFFER iface,
3402         LPDWORD lpdwCapturePosition,
3403         LPDWORD lpdwReadPosition )
3404 {
3405         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3406
3407         FIXME( "(%p)->(%p,%p): stub\n", This, lpdwCapturePosition, lpdwReadPosition );
3408
3409         return DS_OK;
3410 }
3411
3412 static HRESULT WINAPI
3413 IDirectSoundCaptureBufferImpl_GetFormat(
3414         LPDIRECTSOUNDCAPTUREBUFFER iface,
3415         LPWAVEFORMATEX lpwfxFormat, 
3416         DWORD dwSizeAllocated, 
3417         LPDWORD lpdwSizeWritten )
3418 {
3419         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3420
3421         FIXME( "(%p)->(%p,0x%08lx,%p): stub\n", This, lpwfxFormat, dwSizeAllocated, lpdwSizeWritten );
3422
3423         return DS_OK;
3424 }
3425
3426 static HRESULT WINAPI
3427 IDirectSoundCaptureBufferImpl_GetStatus(
3428         LPDIRECTSOUNDCAPTUREBUFFER iface,
3429         LPDWORD lpdwStatus )
3430 {
3431         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3432
3433         FIXME( "(%p)->(%p): stub\n", This, lpdwStatus );
3434
3435         return DS_OK;
3436 }
3437
3438 static HRESULT WINAPI
3439 IDirectSoundCaptureBufferImpl_Initialize(
3440         LPDIRECTSOUNDCAPTUREBUFFER iface,
3441         LPDIRECTSOUNDCAPTURE lpDSC, 
3442         LPCDSCBUFFERDESC lpcDSCBDesc )
3443 {
3444         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3445
3446         FIXME( "(%p)->(%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
3447
3448         return DS_OK;
3449 }
3450
3451 static HRESULT WINAPI
3452 IDirectSoundCaptureBufferImpl_Lock(
3453         LPDIRECTSOUNDCAPTUREBUFFER iface,
3454         DWORD dwReadCusor, 
3455         DWORD dwReadBytes, 
3456         LPVOID* lplpvAudioPtr1, 
3457         LPDWORD lpdwAudioBytes1, 
3458         LPVOID* lplpvAudioPtr2, 
3459         LPDWORD lpdwAudioBytes2, 
3460         DWORD dwFlags )
3461 {
3462         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3463
3464         FIXME( "(%p)->(%08lu,%08lu,%p,%p,%p,%p,0x%08lx): stub\n", This, dwReadCusor, dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2, lpdwAudioBytes2, dwFlags );
3465
3466         return DS_OK;
3467 }
3468
3469 static HRESULT WINAPI
3470 IDirectSoundCaptureBufferImpl_Start(
3471         LPDIRECTSOUNDCAPTUREBUFFER iface,
3472         DWORD dwFlags )
3473 {
3474         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3475
3476         FIXME( "(%p)->(0x%08lx): stub\n", This, dwFlags );
3477
3478         return DS_OK;
3479 }
3480
3481 static HRESULT WINAPI
3482 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER iface )
3483 {
3484         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3485
3486         FIXME( "(%p): stub\n", This );
3487
3488         return DS_OK;
3489 }
3490
3491 static HRESULT WINAPI
3492 IDirectSoundCaptureBufferImpl_Unlock(
3493         LPDIRECTSOUNDCAPTUREBUFFER iface,
3494         LPVOID lpvAudioPtr1, 
3495         DWORD dwAudioBytes1, 
3496         LPVOID lpvAudioPtr2, 
3497         DWORD dwAudioBytes2 )
3498 {
3499         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3500
3501         FIXME( "(%p)->(%p,%08lu,%p,%08lu): stub\n", This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2 );
3502
3503         return DS_OK;
3504 }
3505
3506
3507 static ICOM_VTABLE(IDirectSoundCaptureBuffer) dscbvt =
3508 {
3509         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3510         /* IUnknown methods */
3511         IDirectSoundCaptureBufferImpl_QueryInterface,
3512         IDirectSoundCaptureBufferImpl_AddRef,
3513         IDirectSoundCaptureBufferImpl_Release,
3514
3515         /* IDirectSoundCaptureBuffer methods */
3516         IDirectSoundCaptureBufferImpl_GetCaps,
3517         IDirectSoundCaptureBufferImpl_GetCurrentPosition,
3518         IDirectSoundCaptureBufferImpl_GetFormat,
3519         IDirectSoundCaptureBufferImpl_GetStatus,
3520         IDirectSoundCaptureBufferImpl_Initialize,
3521         IDirectSoundCaptureBufferImpl_Lock,
3522         IDirectSoundCaptureBufferImpl_Start,
3523         IDirectSoundCaptureBufferImpl_Stop,
3524         IDirectSoundCaptureBufferImpl_Unlock
3525 };
3526
3527 /*******************************************************************************
3528  * DirectSound ClassFactory
3529  */
3530 typedef struct
3531 {
3532     /* IUnknown fields */
3533     ICOM_VFIELD(IClassFactory);
3534     DWORD                       ref;
3535 } IClassFactoryImpl;
3536
3537 static HRESULT WINAPI 
3538 DSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
3539         ICOM_THIS(IClassFactoryImpl,iface);
3540
3541         FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
3542         return E_NOINTERFACE;
3543 }
3544
3545 static ULONG WINAPI
3546 DSCF_AddRef(LPCLASSFACTORY iface) {
3547         ICOM_THIS(IClassFactoryImpl,iface);
3548         return ++(This->ref);
3549 }
3550
3551 static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface) {
3552         ICOM_THIS(IClassFactoryImpl,iface);
3553         /* static class, won't be  freed */
3554         return --(This->ref);
3555 }
3556
3557 static HRESULT WINAPI DSCF_CreateInstance(
3558         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
3559 ) {
3560         ICOM_THIS(IClassFactoryImpl,iface);
3561
3562         TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
3563         if ( IsEqualGUID( &IID_IDirectSound, riid ) ) {
3564                 /* FIXME: reuse already created dsound if present? */
3565                 return DirectSoundCreate(riid,(LPDIRECTSOUND*)ppobj,pOuter);
3566         }
3567         return E_NOINTERFACE;
3568 }
3569
3570 static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
3571         ICOM_THIS(IClassFactoryImpl,iface);
3572         FIXME("(%p)->(%d),stub!\n",This,dolock);
3573         return S_OK;
3574 }
3575
3576 static ICOM_VTABLE(IClassFactory) DSCF_Vtbl = {
3577         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3578         DSCF_QueryInterface,
3579         DSCF_AddRef,
3580         DSCF_Release,
3581         DSCF_CreateInstance,
3582         DSCF_LockServer
3583 };
3584 static IClassFactoryImpl DSOUND_CF = {&DSCF_Vtbl, 1 };
3585
3586 /*******************************************************************************
3587  * DllGetClassObject [DSOUND.4]
3588  * Retrieves class object from a DLL object
3589  *
3590  * NOTES
3591  *    Docs say returns STDAPI
3592  *
3593  * PARAMS
3594  *    rclsid [I] CLSID for the class object
3595  *    riid   [I] Reference to identifier of interface for class object
3596  *    ppv    [O] Address of variable to receive interface pointer for riid
3597  *
3598  * RETURNS
3599  *    Success: S_OK
3600  *    Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
3601  *             E_UNEXPECTED
3602  */
3603 DWORD WINAPI DSOUND_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv)
3604 {
3605     TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
3606     if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
3607         *ppv = (LPVOID)&DSOUND_CF;
3608         IClassFactory_AddRef((IClassFactory*)*ppv);
3609     return S_OK;
3610     }
3611
3612     FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
3613     return CLASS_E_CLASSNOTAVAILABLE;
3614 }
3615
3616
3617 /*******************************************************************************
3618  * DllCanUnloadNow [DSOUND.3]  Determines whether the DLL is in use.
3619  *
3620  * RETURNS
3621  *    Success: S_OK
3622  *    Failure: S_FALSE
3623  */
3624 DWORD WINAPI DSOUND_DllCanUnloadNow(void)
3625 {
3626     FIXME("(void): stub\n");
3627     return S_FALSE;
3628 }