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