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