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