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