Fixed some warnings.
[wine] / dlls / dsound / dsound_main.c
1 /*                      DirectSound
2  * 
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998 Rob Riggs
5  * Copyright 2000 Ove Kåven, TransGaming Technologies, Inc.
6  */
7 /*
8  * Most thread locking is complete. There may be a few race
9  * conditions still lurking.
10  *
11  * Tested with a Soundblaster clone, a Gravis UltraSound Classic,
12  * and a Turtle Beach Tropez+.
13  *
14  * TODO:
15  *      Implement DirectSoundCapture API
16  *      Implement SetCooperativeLevel properly (need to address focus issues)
17  *      Implement DirectSound3DBuffers (stubs in place)
18  *      Use hardware 3D support if available
19  *      Add critical section locking inside Release and AddRef methods
20  *      Handle static buffers - put those in hardware, non-static not in hardware
21  *      Hardware DuplicateSoundBuffer
22  *      Proper volume calculation, and setting volume in HEL primary buffer
23  *      Optimize WINMM and negotiate fragment size, decrease DS_HEL_MARGIN
24  */
25
26 #include "config.h"
27 #include <assert.h>
28 #include <errno.h>
29 #include <stdio.h>
30 #include <sys/types.h>
31 #include <sys/time.h>
32 #include <sys/fcntl.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <math.h>       /* Insomnia - pow() function */
37 #include "dsound.h"
38 #include "dsdriver.h"
39 #include "windef.h"
40 #include "wingdi.h"
41 #include "winuser.h"
42 #include "winerror.h"
43 #include "mmsystem.h"
44 #include "wine/obj_base.h"
45 #include "thread.h"
46 #include "debugtools.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.x.x = 0.0;
1736                 dsl->ds3dl.vPosition.x.x = 0.0;
1737                 dsl->ds3dl.vPosition.z.z = 0.0;
1738                 dsl->ds3dl.vVelocity.x.x = 0.0;
1739                 dsl->ds3dl.vVelocity.y.y = 0.0;
1740                 dsl->ds3dl.vVelocity.z.z = 0.0;
1741                 dsl->ds3dl.vOrientFront.x.x = 0.0;
1742                 dsl->ds3dl.vOrientFront.y.y = 0.0;
1743                 dsl->ds3dl.vOrientFront.z.z = 1.0;
1744                 dsl->ds3dl.vOrientTop.x.x = 0.0;
1745                 dsl->ds3dl.vOrientTop.y.y = 1.0;
1746                 dsl->ds3dl.vOrientTop.z.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         /* register buffer */
2028         EnterCriticalSection(&(This->lock));
2029         {
2030                 IDirectSoundBufferImpl **newbuffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl**)*(This->nrofbuffers+1));
2031                 if (newbuffers) {
2032                         This->buffers = newbuffers;
2033                         This->buffers[This->nrofbuffers] = *ippdsb;
2034                         This->nrofbuffers++;
2035                         TRACE("buffer count is now %d\n", This->nrofbuffers);
2036                 } else {
2037                         ERR("out of memory for buffer list! Current buffer count is %d\n", This->nrofbuffers);
2038                         /* FIXME: release buffer */
2039                 }
2040         }
2041         LeaveCriticalSection(&(This->lock));
2042         IDirectSound_AddRef(iface);
2043         return DS_OK;
2044 }
2045
2046
2047 static HRESULT WINAPI IDirectSoundImpl_GetCaps(LPDIRECTSOUND iface,LPDSCAPS caps) {
2048         ICOM_THIS(IDirectSoundImpl,iface);
2049         TRACE("(%p,%p)\n",This,caps);
2050         TRACE("(flags=0x%08lx)\n",caps->dwFlags);
2051
2052         if (caps == NULL)
2053                 return DSERR_INVALIDPARAM;
2054
2055         /* We should check this value, not set it. See Inside DirectX, p215. */
2056         caps->dwSize = sizeof(*caps);
2057
2058         caps->dwFlags = This->drvcaps.dwFlags;
2059
2060         /* FIXME: copy caps from This->drvcaps */
2061         caps->dwMinSecondarySampleRate          = DSBFREQUENCY_MIN;
2062         caps->dwMaxSecondarySampleRate          = DSBFREQUENCY_MAX;
2063
2064         caps->dwPrimaryBuffers                  = 1;
2065
2066         caps->dwMaxHwMixingAllBuffers           = 0;
2067         caps->dwMaxHwMixingStaticBuffers        = 0;
2068         caps->dwMaxHwMixingStreamingBuffers     = 0;
2069
2070         caps->dwFreeHwMixingAllBuffers          = 0;
2071         caps->dwFreeHwMixingStaticBuffers       = 0;
2072         caps->dwFreeHwMixingStreamingBuffers    = 0;
2073
2074         caps->dwMaxHw3DAllBuffers               = 0;
2075         caps->dwMaxHw3DStaticBuffers            = 0;
2076         caps->dwMaxHw3DStreamingBuffers         = 0;
2077
2078         caps->dwFreeHw3DAllBuffers              = 0;
2079         caps->dwFreeHw3DStaticBuffers           = 0;
2080         caps->dwFreeHw3DStreamingBuffers        = 0;
2081
2082         caps->dwTotalHwMemBytes                 = 0;
2083
2084         caps->dwFreeHwMemBytes                  = 0;
2085
2086         caps->dwMaxContigFreeHwMemBytes         = 0;
2087
2088         caps->dwUnlockTransferRateHwBuffers     = 4096; /* But we have none... */
2089
2090         caps->dwPlayCpuOverheadSwBuffers        = 1;    /* 1% */
2091
2092         return DS_OK;
2093 }
2094
2095 static ULONG WINAPI IDirectSoundImpl_AddRef(LPDIRECTSOUND iface) {
2096         ICOM_THIS(IDirectSoundImpl,iface);
2097         return ++(This->ref);
2098 }
2099
2100 static ULONG WINAPI IDirectSoundImpl_Release(LPDIRECTSOUND iface) {
2101         ICOM_THIS(IDirectSoundImpl,iface);
2102         TRACE("(%p), ref was %ld\n",This,This->ref);
2103         if (!--(This->ref)) {
2104                 UINT i;
2105
2106                 timeKillEvent(This->timerID);
2107                 timeEndPeriod(DS_TIME_RES);
2108
2109                 if (primarybuf)
2110                         IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)primarybuf);
2111
2112                 if (This->buffers) {
2113                         for( i=0;i<This->nrofbuffers;i++)       
2114                                 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->buffers[i]);
2115                 }
2116
2117                 if (This->primary)
2118                         IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->primary);
2119
2120                 DeleteCriticalSection(&This->lock);
2121                 if (This->driver) {
2122                         IDsDriver_Close(This->driver);
2123                 } else {
2124                         unsigned c;
2125                         for (c=0; c<DS_HEL_FRAGS; c++)
2126                                 HeapFree(GetProcessHeap(),0,This->pwave[c]);
2127                 }
2128                 if (This->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) {
2129                         waveOutClose(This->hwo);
2130                 }
2131                 if (This->driver)
2132                         IDsDriver_Release(This->driver);
2133
2134                 HeapFree(GetProcessHeap(),0,This);
2135                 dsound = NULL;
2136                 return 0;
2137         }
2138         return This->ref;
2139 }
2140
2141 static HRESULT WINAPI IDirectSoundImpl_SetSpeakerConfig(
2142         LPDIRECTSOUND iface,DWORD config
2143 ) {
2144         ICOM_THIS(IDirectSoundImpl,iface);
2145         FIXME("(%p,0x%08lx):stub\n",This,config);
2146         return DS_OK;
2147 }
2148
2149 static HRESULT WINAPI IDirectSoundImpl_QueryInterface(
2150         LPDIRECTSOUND iface,REFIID riid,LPVOID *ppobj
2151 ) {
2152         ICOM_THIS(IDirectSoundImpl,iface);
2153
2154         if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
2155
2156                 if (This->listener) {
2157                         *ppobj = This->listener;
2158                         IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)This->listener);
2159                         return DS_OK;
2160                 }
2161
2162                 This->listener = (IDirectSound3DListenerImpl*)HeapAlloc(
2163                         GetProcessHeap(), 0, sizeof(*(This->listener)));
2164                 This->listener->ref = 1;
2165                 ICOM_VTBL(This->listener) = &ds3dlvt;
2166                 *ppobj = (LPVOID)This->listener;
2167                 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)*ppobj); 
2168
2169                 This->listener->dsb = NULL; 
2170
2171                 This->listener->ds3dl.dwSize = sizeof(DS3DLISTENER);
2172                 This->listener->ds3dl.vPosition.x.x = 0.0;
2173                 This->listener->ds3dl.vPosition.x.x = 0.0;
2174                 This->listener->ds3dl.vPosition.z.z = 0.0;
2175                 This->listener->ds3dl.vVelocity.x.x = 0.0;
2176                 This->listener->ds3dl.vVelocity.y.y = 0.0;
2177                 This->listener->ds3dl.vVelocity.z.z = 0.0;
2178                 This->listener->ds3dl.vOrientFront.x.x = 0.0;
2179                 This->listener->ds3dl.vOrientFront.y.y = 0.0;
2180                 This->listener->ds3dl.vOrientFront.z.z = 1.0;
2181                 This->listener->ds3dl.vOrientTop.x.x = 0.0;
2182                 This->listener->ds3dl.vOrientTop.y.y = 1.0;
2183                 This->listener->ds3dl.vOrientTop.z.z = 0.0;
2184                 This->listener->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
2185                 This->listener->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
2186                 This->listener->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
2187
2188                 InitializeCriticalSection(&This->listener->lock);
2189
2190                 return DS_OK;
2191         }
2192
2193         FIXME("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
2194         return E_FAIL;
2195 }
2196
2197 static HRESULT WINAPI IDirectSoundImpl_Compact(
2198         LPDIRECTSOUND iface)
2199 {
2200         ICOM_THIS(IDirectSoundImpl,iface);
2201         TRACE("(%p)\n", This);
2202         return DS_OK;
2203 }
2204
2205 static HRESULT WINAPI IDirectSoundImpl_GetSpeakerConfig(
2206         LPDIRECTSOUND iface,
2207         LPDWORD lpdwSpeakerConfig)
2208 {
2209         ICOM_THIS(IDirectSoundImpl,iface);
2210         TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
2211         *lpdwSpeakerConfig = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
2212         return DS_OK;
2213 }
2214
2215 static HRESULT WINAPI IDirectSoundImpl_Initialize(
2216         LPDIRECTSOUND iface,
2217         LPCGUID lpcGuid)
2218 {
2219         ICOM_THIS(IDirectSoundImpl,iface);
2220         TRACE("(%p, %p)\n", This, lpcGuid);
2221         return DS_OK;
2222 }
2223
2224 static ICOM_VTABLE(IDirectSound) dsvt = 
2225 {
2226         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2227         IDirectSoundImpl_QueryInterface,
2228         IDirectSoundImpl_AddRef,
2229         IDirectSoundImpl_Release,
2230         IDirectSoundImpl_CreateSoundBuffer,
2231         IDirectSoundImpl_GetCaps,
2232         IDirectSoundImpl_DuplicateSoundBuffer,
2233         IDirectSoundImpl_SetCooperativeLevel,
2234         IDirectSoundImpl_Compact,
2235         IDirectSoundImpl_GetSpeakerConfig,
2236         IDirectSoundImpl_SetSpeakerConfig,
2237         IDirectSoundImpl_Initialize
2238 };
2239
2240
2241 static void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len)
2242 {
2243         int                     i;
2244         DWORD                   offset;
2245         LPDSBPOSITIONNOTIFY     event;
2246
2247         if (dsb->nrofnotifies == 0)
2248                 return;
2249
2250         TRACE("(%p) buflen = %ld, playpos = %ld, len = %d\n",
2251                 dsb, dsb->buflen, dsb->playpos, len);
2252         for (i = 0; i < dsb->nrofnotifies ; i++) {
2253                 event = dsb->notifies + i;
2254                 offset = event->dwOffset;
2255                 TRACE("checking %d, position %ld, event = %d\n",
2256                         i, offset, event->hEventNotify);
2257                 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
2258                 /* OK. [Inside DirectX, p274] */
2259                 /*  */
2260                 /* This also means we can't sort the entries by offset, */
2261                 /* because DSBPN_OFFSETSTOP == -1 */
2262                 if (offset == DSBPN_OFFSETSTOP) {
2263                         if (dsb->state == STATE_STOPPED) {
2264                                 SetEvent(event->hEventNotify);
2265                                 TRACE("signalled event %d (%d)\n", event->hEventNotify, i);
2266                                 return;
2267                         } else
2268                                 return;
2269                 }
2270                 if ((dsb->playpos + len) >= dsb->buflen) {
2271                         if ((offset < ((dsb->playpos + len) % dsb->buflen)) ||
2272                             (offset >= dsb->playpos)) {
2273                                 TRACE("signalled event %d (%d)\n", event->hEventNotify, i);
2274                                 SetEvent(event->hEventNotify);
2275                         }
2276                 } else {
2277                         if ((offset >= dsb->playpos) && (offset < (dsb->playpos + len))) {
2278                                 TRACE("signalled event %d (%d)\n", event->hEventNotify, i);
2279                                 SetEvent(event->hEventNotify);
2280                         }
2281                 }
2282         }
2283 }
2284
2285 /* WAV format info can be found at: */
2286 /* */
2287 /*      http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
2288 /*      ftp://ftp.cwi.nl/pub/audio/RIFF-format */
2289 /* */
2290 /* Import points to remember: */
2291 /* */
2292 /*      8-bit WAV is unsigned */
2293 /*      16-bit WAV is signed */
2294
2295 static inline INT16 cvtU8toS16(BYTE byte)
2296 {
2297         INT16   s = (byte - 128) << 8;
2298
2299         return s;
2300 }
2301
2302 static inline BYTE cvtS16toU8(INT16 word)
2303 {
2304         BYTE    b = (word + 32768) >> 8;
2305         
2306         return b;
2307 }
2308
2309
2310 /* We should be able to optimize these two inline functions */
2311 /* so that we aren't doing 8->16->8 conversions when it is */
2312 /* not necessary. But this is still a WIP. Optimize later. */
2313 static inline void get_fields(const IDirectSoundBufferImpl *dsb, BYTE *buf, INT *fl, INT *fr)
2314 {
2315         INT16   *bufs = (INT16 *) buf;
2316
2317         /* TRACE("(%p)", buf); */
2318         if ((dsb->wfx.wBitsPerSample == 8) && dsb->wfx.nChannels == 2) {
2319                 *fl = cvtU8toS16(*buf);
2320                 *fr = cvtU8toS16(*(buf + 1));
2321                 return;
2322         }
2323
2324         if ((dsb->wfx.wBitsPerSample == 16) && dsb->wfx.nChannels == 2) {
2325                 *fl = *bufs;
2326                 *fr = *(bufs + 1);
2327                 return;
2328         }
2329
2330         if ((dsb->wfx.wBitsPerSample == 8) && dsb->wfx.nChannels == 1) {
2331                 *fl = cvtU8toS16(*buf);
2332                 *fr = *fl;
2333                 return;
2334         }
2335
2336         if ((dsb->wfx.wBitsPerSample == 16) && dsb->wfx.nChannels == 1) {
2337                 *fl = *bufs;
2338                 *fr = *bufs;
2339                 return;
2340         }
2341
2342         FIXME("get_fields found an unsupported configuration\n");
2343         return;
2344 }
2345
2346 static inline void set_fields(BYTE *buf, INT fl, INT fr)
2347 {
2348         INT16 *bufs = (INT16 *) buf;
2349
2350         if ((primarybuf->wfx.wBitsPerSample == 8) && (primarybuf->wfx.nChannels == 2)) {
2351                 *buf = cvtS16toU8(fl);
2352                 *(buf + 1) = cvtS16toU8(fr);
2353                 return;
2354         }
2355
2356         if ((primarybuf->wfx.wBitsPerSample == 16) && (primarybuf->wfx.nChannels == 2)) {
2357                 *bufs = fl;
2358                 *(bufs + 1) = fr;
2359                 return;
2360         }
2361
2362         if ((primarybuf->wfx.wBitsPerSample == 8) && (primarybuf->wfx.nChannels == 1)) {
2363                 *buf = cvtS16toU8((fl + fr) >> 1);
2364                 return;
2365         }
2366
2367         if ((primarybuf->wfx.wBitsPerSample == 16) && (primarybuf->wfx.nChannels == 1)) {
2368                 *bufs = (fl + fr) >> 1;
2369                 return;
2370         }
2371         FIXME("set_fields found an unsupported configuration\n");
2372         return;
2373 }
2374
2375 /* Now with PerfectPitch (tm) technology */
2376 static INT DSOUND_MixerNorm(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
2377 {
2378         INT     i, size, ipos, ilen, fieldL, fieldR;
2379         BYTE    *ibp, *obp;
2380         INT     iAdvance = dsb->wfx.nBlockAlign;
2381         INT     oAdvance = primarybuf->wfx.nBlockAlign;
2382
2383         ibp = dsb->buffer + dsb->mixpos;
2384         obp = buf;
2385
2386         TRACE("(%p, %p, %p), mixpos=%ld\n", dsb, ibp, obp, dsb->mixpos);
2387         /* Check for the best case */
2388         if ((dsb->freq == primarybuf->wfx.nSamplesPerSec) &&
2389             (dsb->wfx.wBitsPerSample == primarybuf->wfx.wBitsPerSample) &&
2390             (dsb->wfx.nChannels == primarybuf->wfx.nChannels)) {
2391                 DWORD bytesleft = dsb->buflen - dsb->mixpos;
2392                 TRACE("(%p) Best case\n", dsb);
2393                 if (len <= bytesleft )
2394                         memcpy(obp, ibp, len);
2395                 else { /* wrap */
2396                         memcpy(obp, ibp, bytesleft );
2397                         memcpy(obp + bytesleft, dsb->buffer, len - bytesleft);
2398                 }
2399                 return len;
2400         }
2401         
2402         /* Check for same sample rate */
2403         if (dsb->freq == primarybuf->wfx.nSamplesPerSec) {
2404                 TRACE("(%p) Same sample rate %ld = primary %ld\n", dsb,
2405                         dsb->freq, primarybuf->wfx.nSamplesPerSec);
2406                 ilen = 0;
2407                 for (i = 0; i < len; i += oAdvance) {
2408                         get_fields(dsb, ibp, &fieldL, &fieldR);
2409                         ibp += iAdvance;
2410                         ilen += iAdvance;
2411                         set_fields(obp, fieldL, fieldR);
2412                         obp += oAdvance;
2413                         if (ibp >= (BYTE *)(dsb->buffer + dsb->buflen))
2414                                 ibp = dsb->buffer;      /* wrap */
2415                 }
2416                 return (ilen);  
2417         }
2418
2419         /* Mix in different sample rates */
2420         /* */
2421         /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
2422         /* Patent Pending :-] */
2423
2424         TRACE("(%p) Adjusting frequency: %ld -> %ld\n",
2425                 dsb, dsb->freq, primarybuf->wfx.nSamplesPerSec);
2426
2427         size = len / oAdvance;
2428         ilen = ((size * dsb->freqAdjust) >> DSOUND_FREQSHIFT) * iAdvance;
2429         for (i = 0; i < size; i++) {
2430
2431                 ipos = (((i * dsb->freqAdjust) >> DSOUND_FREQSHIFT) * iAdvance) + dsb->mixpos;
2432
2433                 if (ipos >= dsb->buflen)
2434                         ipos %= dsb->buflen;    /* wrap */
2435
2436                 get_fields(dsb, (dsb->buffer + ipos), &fieldL, &fieldR);
2437                 set_fields(obp, fieldL, fieldR);
2438                 obp += oAdvance;
2439         }
2440         return ilen;
2441 }
2442
2443 static void DSOUND_MixerVol(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
2444 {
2445         INT     i, inc = primarybuf->wfx.wBitsPerSample >> 3;
2446         BYTE    *bpc = buf;
2447         INT16   *bps = (INT16 *) buf;
2448         
2449         TRACE("(%p) left = %lx, right = %lx\n", dsb,
2450                 dsb->volpan.dwTotalLeftAmpFactor, dsb->volpan.dwTotalRightAmpFactor);
2451         if ((!(dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || (dsb->volpan.lPan == 0)) &&
2452             (!(dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) || (dsb->volpan.lVolume == 0)) &&
2453             !(dsb->dsbd.dwFlags & DSBCAPS_CTRL3D))
2454                 return;         /* Nothing to do */
2455
2456         /* If we end up with some bozo coder using panning or 3D sound */
2457         /* with a mono primary buffer, it could sound very weird using */
2458         /* this method. Oh well, tough patooties. */
2459
2460         for (i = 0; i < len; i += inc) {
2461                 INT     val;
2462
2463                 switch (inc) {
2464
2465                 case 1:
2466                         /* 8-bit WAV is unsigned, but we need to operate */
2467                         /* on signed data for this to work properly */
2468                         val = *bpc - 128;
2469                         val = ((val * (i & inc ? dsb->volpan.dwTotalRightAmpFactor : dsb->volpan.dwTotalLeftAmpFactor)) >> 16);
2470                         *bpc = val + 128;
2471                         bpc++;
2472                         break;
2473                 case 2:
2474                         /* 16-bit WAV is signed -- much better */
2475                         val = *bps;
2476                         val = ((val * ((i & inc) ? dsb->volpan.dwTotalRightAmpFactor : dsb->volpan.dwTotalLeftAmpFactor)) >> 16);
2477                         *bps = val;
2478                         bps++;
2479                         break;
2480                 default:
2481                         /* Very ugly! */
2482                         FIXME("MixerVol had a nasty error\n");
2483                 }
2484         }               
2485 }
2486
2487 #ifdef USE_DSOUND3D
2488 static void DSOUND_Mixer3D(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
2489 {
2490         BYTE    *ibp, *obp;
2491         DWORD   buflen, mixpos;
2492
2493         buflen = dsb->ds3db->buflen;
2494         mixpos = (dsb->mixpos * primarybuf->wfx.nBlockAlign) / dsb->wfx.nBlockAlign;
2495         ibp = dsb->ds3db->buffer + mixpos;
2496         obp = buf;
2497
2498         if (mixpos > buflen) {
2499                 FIXME("Major breakage");
2500                 return;
2501         }
2502
2503         if (len <= (mixpos + buflen))
2504                 memcpy(obp, ibp, len);
2505         else { /* wrap */
2506                 memcpy(obp, ibp, buflen - mixpos);
2507                 memcpy(obp + (buflen - mixpos),
2508                     dsb->buffer,
2509                     len - (buflen - mixpos));
2510         }
2511         return;
2512 }
2513 #endif
2514
2515 static void *tmp_buffer;
2516 static size_t tmp_buffer_len = 0;
2517
2518 static void *DSOUND_tmpbuffer(size_t len)
2519 {
2520   if (len>tmp_buffer_len) {
2521     void *new_buffer = realloc(tmp_buffer, len);
2522     if (new_buffer) {
2523       tmp_buffer = new_buffer;
2524       tmp_buffer_len = len;
2525     }
2526     return new_buffer;
2527   }
2528   return tmp_buffer;
2529 }
2530
2531 static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD fraglen)
2532 {
2533         INT     i, len, ilen, temp, field;
2534         INT     advance = primarybuf->wfx.wBitsPerSample >> 3;
2535         BYTE    *buf, *ibuf, *obuf;
2536         INT16   *ibufs, *obufs;
2537
2538         len = fraglen;
2539         if (!(dsb->playflags & DSBPLAY_LOOPING)) {
2540                 temp = MulDiv(primarybuf->wfx.nAvgBytesPerSec, dsb->buflen,
2541                         dsb->nAvgBytesPerSec) -
2542                        MulDiv(primarybuf->wfx.nAvgBytesPerSec, dsb->mixpos,
2543                         dsb->nAvgBytesPerSec);
2544                 len = (len > temp) ? temp : len;
2545         }
2546         len &= ~3;                              /* 4 byte alignment */
2547
2548         if (len == 0) {
2549                 /* This should only happen if we aren't looping and temp < 4 */
2550
2551                 /* We skip the remainder, so check for possible events */
2552                 DSOUND_CheckEvent(dsb, dsb->buflen - dsb->mixpos);
2553                 /* Stop */
2554                 dsb->state = STATE_STOPPED;
2555                 dsb->playpos = 0;
2556                 dsb->mixpos = 0;
2557                 dsb->leadin = FALSE;
2558                 /* Check for DSBPN_OFFSETSTOP */
2559                 DSOUND_CheckEvent(dsb, 0);
2560                 return 0;
2561         }
2562
2563         /* Been seeing segfaults in malloc() for some reason... */
2564         TRACE("allocating buffer (size = %d)\n", len);
2565         if ((buf = ibuf = (BYTE *) DSOUND_tmpbuffer(len)) == NULL)
2566                 return 0;
2567
2568         TRACE("MixInBuffer (%p) len = %d, dest = %ld\n", dsb, len, writepos);
2569
2570         ilen = DSOUND_MixerNorm(dsb, ibuf, len);
2571         if ((dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
2572             (dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME))
2573                 DSOUND_MixerVol(dsb, ibuf, len);
2574
2575         obuf = primarybuf->buffer + writepos;
2576         for (i = 0; i < len; i += advance) {
2577                 obufs = (INT16 *) obuf;
2578                 ibufs = (INT16 *) ibuf;
2579                 if (primarybuf->wfx.wBitsPerSample == 8) {
2580                         /* 8-bit WAV is unsigned */
2581                         field = (*ibuf - 128);
2582                         field += (*obuf - 128);
2583                         field = field > 127 ? 127 : field;
2584                         field = field < -128 ? -128 : field;
2585                         *obuf = field + 128;
2586                 } else {
2587                         /* 16-bit WAV is signed */
2588                         field = *ibufs;
2589                         field += *obufs;
2590                         field = field > 32767 ? 32767 : field;
2591                         field = field < -32768 ? -32768 : field;
2592                         *obufs = field;
2593                 }
2594                 ibuf += advance;
2595                 obuf += advance;
2596                 if (obuf >= (BYTE *)(primarybuf->buffer + primarybuf->buflen))
2597                         obuf = primarybuf->buffer;
2598         }
2599         /* free(buf); */
2600
2601         if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY)
2602                 DSOUND_CheckEvent(dsb, ilen);
2603
2604         if (dsb->leadin && (dsb->startpos > dsb->mixpos) && (dsb->startpos <= dsb->mixpos + ilen)) {
2605                 /* HACK... leadin should be reset when the PLAY position reaches the startpos,
2606                  * not the MIX position... but if the sound buffer is bigger than our prebuffering
2607                  * (which must be the case for the streaming buffers that need this hack anyway)
2608                  * plus DS_HEL_MARGIN or equivalent, then this ought to work anyway. */
2609                 dsb->leadin = FALSE;
2610         }
2611
2612         dsb->mixpos += ilen;
2613         
2614         if (dsb->mixpos >= dsb->buflen) {
2615                 if (!(dsb->playflags & DSBPLAY_LOOPING)) {
2616                         dsb->state = STATE_STOPPED;
2617                         dsb->playpos = 0;
2618                         dsb->mixpos = 0;
2619                         dsb->leadin = FALSE;
2620                         DSOUND_CheckEvent(dsb, 0);              /* For DSBPN_OFFSETSTOP */
2621                 } else {
2622                         /* wrap */
2623                         while (dsb->mixpos >= dsb->buflen)
2624                                 dsb->mixpos -= dsb->buflen;
2625                         if (dsb->leadin && (dsb->startpos <= dsb->mixpos))
2626                                 dsb->leadin = FALSE; /* HACK: see above */
2627                 }
2628         }
2629
2630         return len;
2631 }
2632
2633 static DWORD WINAPI DSOUND_MixPrimary(DWORD writepos, DWORD fraglen, BOOL starting)
2634 {
2635         INT                     i, len, maxlen = 0;
2636         IDirectSoundBufferImpl  *dsb;
2637
2638         TRACE("(%ld,%ld,%d)\n", writepos, fraglen, starting);
2639         for (i = dsound->nrofbuffers - 1; i >= 0; i--) {
2640                 dsb = dsound->buffers[i];
2641
2642                 if (!dsb || !(ICOM_VTBL(dsb)))
2643                         continue;
2644                 if (dsb->buflen && dsb->state && !(starting && (dsb->state != STATE_STARTING))) {
2645                         TRACE("Checking %p\n", dsb);
2646                         EnterCriticalSection(&(dsb->lock));
2647                         if (dsb->state == STATE_STOPPING) {
2648                                 /* FIXME: perhaps attempt to remove the buffer from the prebuffer */
2649                                 dsb->state = STATE_STOPPED;
2650                         } else {
2651                                 len = DSOUND_MixInBuffer(dsb, writepos, fraglen);
2652                                 maxlen = len > maxlen ? len : maxlen;
2653                         }
2654                         LeaveCriticalSection(&(dsb->lock));
2655                 }
2656         }
2657         
2658         return maxlen;
2659 }
2660
2661 static void WINAPI DSOUND_MarkPlaying(void)
2662 {
2663         INT                     i;
2664         IDirectSoundBufferImpl  *dsb;
2665
2666         for (i = dsound->nrofbuffers - 1; i >= 0; i--) {
2667                 dsb = dsound->buffers[i];
2668
2669                 if (!dsb || !(ICOM_VTBL(dsb)))
2670                         continue;
2671                 if (dsb->buflen && (dsb->state == STATE_STARTING))
2672                         dsb->state = STATE_PLAYING;
2673         }
2674 }
2675
2676 static void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2)
2677 {
2678         DWORD len;
2679         int nfiller;
2680         BOOL forced;
2681
2682         if (!dsound || !primarybuf) {
2683                 ERR("dsound died without killing us?\n");
2684                 timeKillEvent(timerID);
2685                 timeEndPeriod(DS_TIME_RES);
2686                 return;
2687         }
2688
2689         EnterCriticalSection(&(dsound->lock));
2690
2691         if (!primarybuf || !primarybuf->ref) {
2692                 /* seems the primary buffer is currently being released */
2693                 LeaveCriticalSection(&(dsound->lock));
2694                 return;
2695         }
2696
2697         /* the sound of silence */
2698         nfiller = primarybuf->wfx.wBitsPerSample == 8 ? 128 : 0;
2699
2700         /* whether the primary is forced to play even without secondary buffers */
2701         forced = ((primarybuf->state == STATE_PLAYING) || (primarybuf->state == STATE_STARTING));
2702
2703         if (primarybuf->hwbuf) {
2704                 if (dsound->priolevel != DSSCL_WRITEPRIMARY) {
2705                         BOOL paused = ((primarybuf->state == STATE_STOPPED) || (primarybuf->state == STATE_STARTING));
2706                         DWORD playpos, writepos, inq, maxq, mixq, frag;
2707                         IDsDriverBuffer_GetPosition(primarybuf->hwbuf, &playpos, &writepos);
2708                         /* Well, we *could* do Just-In-Time mixing using the writepos,
2709                          * but that's a little bit ambitious and unnecessary... */
2710                         /* rather add our safety margin to the writepos, if we're playing */
2711                         if (!paused) {
2712                                 writepos += primarybuf->writelead;
2713                                 while (writepos >= primarybuf->buflen)
2714                                         writepos -= primarybuf->buflen;
2715                         } else writepos = playpos;
2716                         TRACE("primary playpos=%ld, writepos=%ld, clrpos=%ld, mixpos=%ld\n",
2717                               playpos,writepos,primarybuf->playpos,primarybuf->mixpos);
2718                         /* wipe out just-played sound data */
2719                         if (playpos < primarybuf->playpos) {
2720                                 memset(primarybuf->buffer + primarybuf->playpos, nfiller, primarybuf->buflen - primarybuf->playpos);
2721                                 memset(primarybuf->buffer, nfiller, playpos);
2722                         } else {
2723                                 memset(primarybuf->buffer + primarybuf->playpos, nfiller, playpos - primarybuf->playpos);
2724                         }
2725                         primarybuf->playpos = playpos;
2726
2727                         /* check how much prebuffering is left */
2728                         inq = primarybuf->mixpos;
2729                         if (inq < writepos)
2730                                 inq += primarybuf->buflen;
2731                         inq -= writepos;
2732
2733                         /* find the maximum we can prebuffer */
2734                         if (!paused) {
2735                                 maxq = playpos;
2736                                 if (maxq < writepos)
2737                                         maxq += primarybuf->buflen;
2738                                 maxq -= writepos;
2739                         } else maxq = primarybuf->buflen;
2740
2741                         /* clip maxq to DS_HAL_QUEUE */
2742                         frag = DS_HAL_QUEUE * dsound->fraglen;
2743                         if (maxq > frag) maxq = frag;
2744
2745                         EnterCriticalSection(&(primarybuf->lock));
2746
2747                         /* check for consistency */
2748                         if (inq > maxq) {
2749                                 /* the playback position must have passed our last
2750                                  * mixed position, i.e. it's an underrun, or we have
2751                                  * nothing more to play */
2752                                 inq = 0;
2753                                 /* stop the playback now, to allow buffers to refill */
2754                                 IDsDriverBuffer_Stop(primarybuf->hwbuf);
2755                                 if (primarybuf->state == STATE_PLAYING) {
2756                                         primarybuf->state = STATE_STARTING;
2757                                 }
2758                                 else if (primarybuf->state == STATE_STOPPING) {
2759                                         primarybuf->state = STATE_STOPPED;
2760                                 }
2761                                 else {
2762                                         /* how can we have an underrun if we aren't playing? */
2763                                         ERR("unexpected primary state (%ld)\n", primarybuf->state);
2764                                 }
2765                                 /* the Stop is supposed to reset play position to beginning of buffer */
2766                                 /* unfortunately, OSS is not able to do so, so get current pointer */
2767                                 IDsDriverBuffer_GetPosition(primarybuf->hwbuf, &playpos, NULL);
2768                                 writepos = playpos;
2769                                 primarybuf->playpos = playpos;
2770                                 primarybuf->mixpos = playpos;
2771                                 inq = 0;
2772                                 maxq = primarybuf->buflen;
2773                                 if (maxq > frag) maxq = frag;
2774                                 memset(primarybuf->buffer, nfiller, primarybuf->buflen);
2775                                 paused = TRUE;
2776                         }
2777
2778                         /* see if some new buffers have been started that we want to merge into our prebuffer;
2779                          * this should minimize latency even when we have a large prebuffer */
2780                         if (!paused) {
2781                                 if (primarybuf->mixpos < writepos) {
2782                                         /* mix to end of buffer */
2783                                         len = DSOUND_MixPrimary(writepos, primarybuf->buflen - writepos, TRUE);
2784                                         if ((len + writepos) < primarybuf->buflen)
2785                                                 goto addmix_complete;
2786                                         /* mix from beginning of buffer */
2787                                         if (primarybuf->mixpos)
2788                                                 len = DSOUND_MixPrimary(0, primarybuf->mixpos, TRUE);
2789                                 } else {
2790                                         /* mix middle of buffer */
2791                                         len = DSOUND_MixPrimary(writepos, primarybuf->mixpos - writepos, TRUE);
2792                                 }
2793                         }
2794                 addmix_complete:
2795                         DSOUND_MarkPlaying();
2796
2797                         mixq = maxq - inq;
2798                         TRACE("queued %ld, max %ld, mixing %ld, paused %d\n", inq, maxq, mixq, paused);
2799                         /* it's too inefficient to mix less than a fragment at a time */
2800                         if (mixq >= dsound->fraglen) {
2801
2802 #define FRAG_MIXER \
2803         if (frag > mixq) frag = mixq; \
2804         len = DSOUND_MixPrimary(primarybuf->mixpos, frag, FALSE); \
2805         if (forced) len = frag; \
2806         primarybuf->mixpos += len; \
2807         mixq -= len; inq += len
2808
2809                                 if ((playpos < writepos) || (paused && (playpos == writepos))) {
2810                                         if (primarybuf->mixpos) {
2811                                                 /* mix to end of buffer */
2812                                                 frag = primarybuf->buflen - primarybuf->mixpos;
2813                                                 FRAG_MIXER;
2814                                                 if (primarybuf->mixpos < primarybuf->buflen)
2815                                                         goto mix_complete;
2816                                                 primarybuf->mixpos = 0;
2817                                         }
2818                                         if (mixq >= dsound->fraglen) {
2819                                                 /* mix from beginning of buffer */
2820                                                 frag = playpos;
2821                                                 if ((!frag) && paused) frag = primarybuf->buflen;
2822                                                 FRAG_MIXER;
2823                                         }
2824                                 }
2825                                 else if (playpos > writepos) {
2826                                         /* mix middle of buffer */
2827                                         frag = playpos - primarybuf->mixpos;
2828                                         FRAG_MIXER;
2829                                 }
2830                                 else {
2831                                         /* this should preferably not happen... */
2832                                         ERR("mixer malfunction (ambiguous writepos)!\n");
2833                                 }
2834 #undef FRAG_MIXER
2835                         }
2836                 mix_complete:
2837                         if (inq) {
2838                                 /* buffers have been filled, restart playback */
2839                                 if (primarybuf->state == STATE_STARTING) {
2840                                         IDsDriverBuffer_Play(primarybuf->hwbuf, 0, 0, DSBPLAY_LOOPING);
2841                                         primarybuf->state = STATE_PLAYING;
2842                                 }
2843                                 else if (primarybuf->state == STATE_STOPPED) {
2844                                         /* the primarybuf is supposed to play if there's something to play
2845                                          * even if it is reported as stopped, so don't let this confuse you */
2846                                         IDsDriverBuffer_Play(primarybuf->hwbuf, 0, 0, DSBPLAY_LOOPING);
2847                                         primarybuf->state = STATE_STOPPING;
2848                                 }
2849                         }
2850                         LeaveCriticalSection(&(primarybuf->lock));
2851                 } else {
2852                         /* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */
2853                         if (primarybuf->state == STATE_STARTING) {
2854                                 IDsDriverBuffer_Play(primarybuf->hwbuf, 0, 0, DSBPLAY_LOOPING);
2855                                 primarybuf->state = STATE_PLAYING;
2856                         } 
2857                         else if (primarybuf->state == STATE_STOPPING) {
2858                                 IDsDriverBuffer_Stop(primarybuf->hwbuf);
2859                                 primarybuf->state = STATE_STOPPED;
2860                         }
2861                 }
2862         } else {
2863                 /* using waveOut stuff */
2864                 /* if no buffers are playing, we should be in pause mode now */
2865                 DWORD writepos;
2866                 /* clean out completed fragments */
2867                 while (dsound->pwqueue && (dsound->pwave[dsound->pwplay]->dwFlags & WHDR_DONE)) {
2868                         if (dsound->priolevel != DSSCL_WRITEPRIMARY) {
2869                                 DWORD pos = dsound->pwplay * dsound->fraglen;
2870                                 TRACE("done playing primary pos=%ld\n",pos);
2871                                 memset(primarybuf->buffer + pos, nfiller, dsound->fraglen);
2872                         }
2873                         dsound->pwplay++;
2874                         if (dsound->pwplay >= DS_HEL_FRAGS) dsound->pwplay = 0;
2875                         dsound->pwqueue--;
2876                 }
2877                 primarybuf->playpos = dsound->pwplay * dsound->fraglen;
2878                 TRACE("primary playpos=%ld, mixpos=%ld\n",primarybuf->playpos,primarybuf->mixpos);
2879                 EnterCriticalSection(&(primarybuf->lock));
2880                 if (!dsound->pwqueue) {
2881                         /* this is either an underrun or we have nothing more to play...
2882                          * since playback has already stopped now, we can enter pause mode,
2883                          * in order to allow buffers to refill */
2884                         if (primarybuf->state == STATE_PLAYING) {
2885                                 waveOutPause(dsound->hwo);
2886                                 primarybuf->state = STATE_STARTING;
2887                         }
2888                         else if (primarybuf->state == STATE_STOPPING) {
2889                                 waveOutPause(dsound->hwo);
2890                                 primarybuf->state = STATE_STOPPED;
2891                         }
2892                 }
2893
2894                 /* find next write position, plus some extra margin */
2895                 writepos = primarybuf->playpos + DS_HEL_MARGIN * dsound->fraglen;
2896                 while (writepos >= primarybuf->buflen) writepos -= primarybuf->buflen;
2897
2898                 /* see if some new buffers have been started that we want to merge into our prebuffer;
2899                  * this should minimize latency even when we have a large prebuffer */
2900                 if (dsound->priolevel != DSSCL_WRITEPRIMARY) {
2901                         if ((primarybuf->state == STATE_PLAYING) || (primarybuf->state == STATE_STOPPING)) {
2902                                 while (writepos != primarybuf->mixpos) {
2903                                         len = DSOUND_MixPrimary(writepos, dsound->fraglen, TRUE);
2904                                         if (!len) break;
2905                                         writepos += dsound->fraglen;
2906                                         if (writepos >= primarybuf->buflen)
2907                                                 writepos -= primarybuf->buflen;
2908                                 }
2909                         }
2910                         DSOUND_MarkPlaying();
2911                 }
2912
2913                 /* we want at least DS_HEL_QUEUE fragments in the prebuffer outqueue;
2914                  * mix a bunch of fragments now as necessary */
2915                 while (dsound->pwqueue < DS_HEL_QUEUE) {
2916                         if (dsound->priolevel != DSSCL_WRITEPRIMARY) {
2917                                 len = DSOUND_MixPrimary(primarybuf->mixpos, dsound->fraglen, FALSE);
2918                         } else len=0;
2919                         if (forced) len = dsound->fraglen;
2920                         /* if we have nothing to play, don't bother to */
2921                         if (!len) break;
2922                         if (len < dsound->fraglen) {
2923                                 TRACE("len=%ld is less than fraglen=%ld\n",len,dsound->fraglen);
2924                         }
2925                         /* ok, we have something to play */
2926                         /* advance mix positions */
2927                         primarybuf->mixpos += dsound->fraglen;
2928                         if (primarybuf->mixpos >= primarybuf->buflen)
2929                                 primarybuf->mixpos -= primarybuf->buflen;
2930                         /* output it */
2931                         waveOutWrite(dsound->hwo, dsound->pwave[dsound->pwwrite], sizeof(WAVEHDR));
2932                         dsound->pwwrite++;
2933                         if (dsound->pwwrite >= DS_HEL_FRAGS) dsound->pwwrite = 0;
2934                         dsound->pwqueue++;
2935                 }
2936                 if (dsound->pwqueue) {
2937                         /* buffers have been filled, restart playback */
2938                         if (primarybuf->state == STATE_STARTING) {
2939                                 waveOutRestart(dsound->hwo);
2940                                 primarybuf->state = STATE_PLAYING;
2941                         }
2942                         else if (primarybuf->state == STATE_STOPPED) {
2943                                 /* the primarybuf is supposed to play if there's something to play
2944                                  * even if it is reported as stopped, so don't let this confuse you */
2945                                 waveOutRestart(dsound->hwo);
2946                                 primarybuf->state = STATE_STOPPING;
2947                         }
2948                 }
2949                 LeaveCriticalSection(&(primarybuf->lock));
2950         }
2951         LeaveCriticalSection(&(dsound->lock));
2952 }
2953
2954 /*******************************************************************************
2955  *              DirectSoundCreate
2956  */
2957 HRESULT WINAPI DirectSoundCreate(REFGUID lpGUID,LPDIRECTSOUND *ppDS,IUnknown *pUnkOuter )
2958 {
2959         IDirectSoundImpl** ippDS=(IDirectSoundImpl**)ppDS;
2960         PIDSDRIVER drv = NULL;
2961         WAVEOUTCAPSA wcaps;
2962         unsigned wod, wodn;
2963         HRESULT err = DS_OK;
2964
2965         if (lpGUID)
2966                 TRACE("(%p,%p,%p)\n",lpGUID,ippDS,pUnkOuter);
2967         else
2968                 TRACE("DirectSoundCreate (%p)\n", ippDS);
2969
2970         if (ippDS == NULL)
2971                 return DSERR_INVALIDPARAM;
2972
2973         if (primarybuf) {
2974                 IDirectSound_AddRef((LPDIRECTSOUND)dsound);
2975                 *ippDS = dsound;
2976                 return DS_OK;
2977         }
2978
2979         /* Enumerate WINMM audio devices and find the one we want */
2980         wodn = waveOutGetNumDevs();
2981         if (!wodn) return DSERR_NODRIVER;
2982
2983         /* FIXME: How do we find the GUID of an audio device? */
2984         /* Well, just use the first available device for now... */
2985         wod = 0;
2986         /* Get output device caps */
2987         waveOutGetDevCapsA(wod, &wcaps, sizeof(wcaps));
2988         /* 0x810 is a "Wine extension" to get the DSound interface */
2989         waveOutMessage(wod, 0x810, (DWORD)&drv, 0);
2990
2991         /* Allocate memory */
2992         *ippDS = (IDirectSoundImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundImpl));
2993         if (*ippDS == NULL)
2994                 return DSERR_OUTOFMEMORY;
2995
2996         ICOM_VTBL(*ippDS)       = &dsvt;
2997         (*ippDS)->ref           = 1;
2998
2999         (*ippDS)->driver        = drv;
3000         (*ippDS)->fraglen       = 0;
3001         (*ippDS)->priolevel     = DSSCL_NORMAL; 
3002         (*ippDS)->nrofbuffers   = 0;
3003         (*ippDS)->buffers       = NULL;
3004         (*ippDS)->primary       = NULL; 
3005         (*ippDS)->listener      = NULL; 
3006
3007         /* Get driver description */
3008         if (drv) {
3009                 IDsDriver_GetDriverDesc(drv,&((*ippDS)->drvdesc));
3010         } else {
3011                 /* if no DirectSound interface available, use WINMM API instead */
3012                 (*ippDS)->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT;
3013                 (*ippDS)->drvdesc.dnDevNode = wod; /* FIXME? */
3014         }
3015
3016         /* Set default wave format (may need it for waveOutOpen) */
3017         (*ippDS)->wfx.wFormatTag        = WAVE_FORMAT_PCM;
3018         (*ippDS)->wfx.nChannels         = 2;
3019         (*ippDS)->wfx.nSamplesPerSec    = 22050;
3020         (*ippDS)->wfx.nAvgBytesPerSec   = 44100;
3021         (*ippDS)->wfx.nBlockAlign       = 2;
3022         (*ippDS)->wfx.wBitsPerSample    = 8;
3023
3024         /* If the driver requests being opened through MMSYSTEM
3025          * (which is recommended by the DDK), it is supposed to happen
3026          * before the DirectSound interface is opened */
3027         if ((*ippDS)->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) {
3028                 /* FIXME: is this right? */
3029                 err = mmErr(waveOutOpen(&((*ippDS)->hwo), (*ippDS)->drvdesc.dnDevNode, &((*ippDS)->wfx),
3030                                         0, 0, CALLBACK_NULL | WAVE_DIRECTSOUND));
3031         }
3032
3033         if (drv && (err == DS_OK))
3034                 err = IDsDriver_Open(drv);
3035
3036         /* FIXME: do we want to handle a temporarily busy device? */
3037         if (err != DS_OK) {
3038                 HeapFree(GetProcessHeap(),0,*ippDS);
3039                 *ippDS = NULL;
3040                 return err;
3041         }
3042
3043         /* the driver is now open, so it's now allowed to call GetCaps */
3044         if (drv) {
3045                 IDsDriver_GetCaps(drv,&((*ippDS)->drvcaps));
3046         } else {
3047                 unsigned c;
3048
3049                 /* FIXME: look at wcaps */
3050                 (*ippDS)->drvcaps.dwFlags = DSCAPS_EMULDRIVER |
3051                         DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO;
3052
3053                 /* Allocate memory for HEL buffer headers */
3054                 for (c=0; c<DS_HEL_FRAGS; c++) {
3055                         (*ippDS)->pwave[c] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEHDR));
3056                         if (!(*ippDS)->pwave[c]) {
3057                                 /* Argh, out of memory */
3058                                 while (c--) {
3059                                         HeapFree(GetProcessHeap(),0,(*ippDS)->pwave[c]);
3060                                         waveOutClose((*ippDS)->hwo);
3061                                         HeapFree(GetProcessHeap(),0,*ippDS);
3062                                         *ippDS = NULL;
3063                                         return DSERR_OUTOFMEMORY;
3064                                 }
3065                         }
3066                 }
3067         }
3068
3069         InitializeCriticalSection(&((*ippDS)->lock));
3070
3071         if (!dsound) {
3072                 dsound = (*ippDS);
3073                 if (primarybuf == NULL) {
3074                         DSBUFFERDESC    dsbd;
3075                         HRESULT         hr;
3076
3077                         dsbd.dwSize = sizeof(DSBUFFERDESC);
3078                         dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2;
3079                         dsbd.dwBufferBytes = 0;
3080                         dsbd.lpwfxFormat = &(dsound->wfx);
3081                         hr = IDirectSound_CreateSoundBuffer(*ppDS, &dsbd, (LPDIRECTSOUNDBUFFER*)&primarybuf, NULL);
3082                         if (hr != DS_OK)
3083                                 return hr;
3084
3085                         /* dsound->primary is NULL - don't need to Release */
3086                         dsound->primary = primarybuf;
3087                         IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)primarybuf);
3088                 }
3089                 timeBeginPeriod(DS_TIME_RES);
3090                 dsound->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, DSOUND_timer,
3091                                                (DWORD)dsound, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
3092         }
3093         return DS_OK;
3094 }
3095
3096 /***************************************************************************
3097  * DirectSoundCaptureCreate [DSOUND.6]
3098  *
3099  * Create and initialize a DirectSoundCapture interface
3100  *
3101  * RETURNS
3102  *    Success: DS_OK
3103  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
3104  *             DSERR_OUTOFMEMORY
3105  */
3106 HRESULT WINAPI DirectSoundCaptureCreate(
3107         LPCGUID lpcGUID,
3108         LPDIRECTSOUNDCAPTURE* lplpDSC,
3109         LPUNKNOWN pUnkOuter )
3110 {
3111         TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), lplpDSC, pUnkOuter);
3112
3113         if( pUnkOuter ) {
3114                 return DSERR_NOAGGREGATION;
3115         }
3116
3117         /* Default device? */
3118         if ( !lpcGUID ) {
3119                 return DSOUND_CreateDirectSoundCapture( (LPVOID*)lplpDSC );
3120         }
3121
3122         FIXME( "Unknown GUID %s\n", debugstr_guid(lpcGUID) );
3123         *lplpDSC = NULL;
3124
3125         return DSERR_OUTOFMEMORY;
3126 }
3127
3128 /***************************************************************************
3129  * DirectSoundCaptureEnumerateA [DSOUND.7]
3130  *
3131  * Enumerate all DirectSound drivers installed in the system
3132  *
3133  * RETURNS
3134  *    Success: DS_OK
3135  *    Failure: DSERR_INVALIDPARAM
3136  */
3137 HRESULT WINAPI DirectSoundCaptureEnumerateA(
3138         LPDSENUMCALLBACKA lpDSEnumCallback,
3139         LPVOID lpContext)
3140 {
3141         TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
3142
3143         if ( lpDSEnumCallback )
3144                 lpDSEnumCallback(NULL,"WINE Primary Sound Capture Driver",
3145                     "SoundCap",lpContext);
3146
3147
3148         return DS_OK;
3149 }
3150
3151 /***************************************************************************
3152  * DirectSoundCaptureEnumerateW [DSOUND.8]
3153  *
3154  * Enumerate all DirectSound drivers installed in the system
3155  *
3156  * RETURNS
3157  *    Success: DS_OK
3158  *    Failure: DSERR_INVALIDPARAM
3159  */
3160 HRESULT WINAPI DirectSoundCaptureEnumerateW(
3161         LPDSENUMCALLBACKW lpDSEnumCallback,
3162         LPVOID lpContext)
3163 {
3164         FIXME("(%p,%p):stub\n", lpDSEnumCallback, lpContext );
3165         return DS_OK;
3166
3167
3168 static HRESULT
3169 DSOUND_CreateDirectSoundCapture( LPVOID* ppobj )
3170 {
3171         *ppobj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( IDirectSoundCaptureImpl ) );
3172
3173         if ( *ppobj == NULL ) {
3174                 return DSERR_OUTOFMEMORY;
3175         }
3176
3177         {
3178                 ICOM_THIS(IDirectSoundCaptureImpl,*ppobj);
3179
3180                 This->ref = 1;
3181                 ICOM_VTBL(This) = &dscvt;
3182
3183                 InitializeCriticalSection( &This->lock );
3184         }
3185
3186         return S_OK;
3187 }
3188
3189 static HRESULT
3190 IDirectSoundCaptureImpl_QueryInterface(
3191         LPDIRECTSOUNDCAPTURE iface,
3192         REFIID riid,
3193         LPVOID* ppobj )
3194 {
3195         ICOM_THIS(IDirectSoundCaptureImpl,iface);
3196
3197         FIXME( "(%p)->(%s,%p): stub\n", This, debugstr_guid(riid), ppobj );
3198
3199         return E_FAIL;
3200 }
3201
3202 static ULONG
3203 IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface )
3204 {
3205         ULONG uRef;
3206         ICOM_THIS(IDirectSoundCaptureImpl,iface);
3207
3208         EnterCriticalSection( &This->lock );
3209
3210         TRACE( "(%p) was 0x%08lx\n", This, This->ref );
3211         uRef = ++(This->ref);
3212
3213         LeaveCriticalSection( &This->lock );
3214
3215         return uRef;
3216 }
3217
3218 static ULONG
3219 IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface )
3220 {
3221         ULONG uRef;
3222         ICOM_THIS(IDirectSoundCaptureImpl,iface);
3223
3224         EnterCriticalSection( &This->lock );
3225
3226         TRACE( "(%p) was 0x%08lx\n", This, This->ref );
3227         uRef = --(This->ref);
3228
3229         LeaveCriticalSection( &This->lock );
3230
3231         if ( uRef == 0 ) {
3232                 DeleteCriticalSection( &This->lock );
3233                 HeapFree( GetProcessHeap(), 0, This );
3234         }
3235
3236         return uRef;
3237 }
3238
3239 static HRESULT
3240 IDirectSoundCaptureImpl_CreateCaptureBuffer(
3241         LPDIRECTSOUNDCAPTURE iface,
3242         LPCDSCBUFFERDESC lpcDSCBufferDesc,
3243         LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer, 
3244         LPUNKNOWN pUnk )
3245 {
3246         HRESULT hr;
3247         ICOM_THIS(IDirectSoundCaptureImpl,iface);
3248
3249         TRACE( "(%p)->(%p,%p,%p)\n", This, lpcDSCBufferDesc, lplpDSCaptureBuffer, pUnk );
3250
3251         if ( pUnk ) {
3252                 return DSERR_INVALIDPARAM;
3253         }
3254
3255         hr = DSOUND_CreateDirectSoundCaptureBuffer( lpcDSCBufferDesc, (LPVOID*)lplpDSCaptureBuffer );
3256
3257         return hr;
3258 }
3259
3260 static HRESULT
3261 IDirectSoundCaptureImpl_GetCaps(
3262         LPDIRECTSOUNDCAPTURE iface,
3263         LPDSCCAPS lpDSCCaps )
3264 {
3265         ICOM_THIS(IDirectSoundCaptureImpl,iface);
3266
3267         FIXME( "(%p)->(%p): stub\n", This, lpDSCCaps );
3268
3269         return DS_OK;
3270 }
3271
3272 static HRESULT
3273 IDirectSoundCaptureImpl_Initialize(
3274         LPDIRECTSOUNDCAPTURE iface,
3275         LPCGUID lpcGUID )
3276 {
3277         ICOM_THIS(IDirectSoundCaptureImpl,iface);
3278
3279         FIXME( "(%p)->(%p): stub\n", This, lpcGUID );
3280
3281         return DS_OK;
3282 }
3283
3284
3285 static ICOM_VTABLE(IDirectSoundCapture) dscvt =
3286 {
3287         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3288         /* IUnknown methods */
3289         IDirectSoundCaptureImpl_QueryInterface,
3290         IDirectSoundCaptureImpl_AddRef,
3291         IDirectSoundCaptureImpl_Release,
3292
3293         /* IDirectSoundCapture methods */
3294         IDirectSoundCaptureImpl_CreateCaptureBuffer,
3295         IDirectSoundCaptureImpl_GetCaps,
3296         IDirectSoundCaptureImpl_Initialize 
3297 };
3298
3299 static HRESULT 
3300 DSOUND_CreateDirectSoundCaptureBuffer( LPCDSCBUFFERDESC lpcDSCBufferDesc, LPVOID* ppobj )
3301 {
3302
3303         FIXME( "(%p,%p): ignoring lpcDSCBufferDesc\n", lpcDSCBufferDesc, ppobj );
3304
3305         *ppobj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( IDirectSoundCaptureBufferImpl ) );
3306
3307         if ( *ppobj == NULL ) {
3308                 return DSERR_OUTOFMEMORY;
3309         }
3310
3311         {
3312                 ICOM_THIS(IDirectSoundCaptureBufferImpl,*ppobj);
3313
3314                 This->ref = 1;
3315                 ICOM_VTBL(This) = &dscbvt;
3316
3317                 InitializeCriticalSection( &This->lock );
3318         }
3319
3320         return S_OK;
3321 }
3322
3323
3324 static HRESULT
3325 IDirectSoundCaptureBufferImpl_QueryInterface(
3326         LPDIRECTSOUNDCAPTUREBUFFER iface,
3327         REFIID riid,
3328         LPVOID* ppobj )
3329 {
3330         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3331
3332         FIXME( "(%p)->(%s,%p): stub\n", This, debugstr_guid(riid), ppobj );
3333
3334         return E_FAIL;
3335 }
3336
3337 static ULONG
3338 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER iface )
3339 {
3340         ULONG uRef;
3341         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3342
3343         EnterCriticalSection( &This->lock );
3344
3345         TRACE( "(%p) was 0x%08lx\n", This, This->ref );
3346         uRef = ++(This->ref);
3347
3348         LeaveCriticalSection( &This->lock );
3349
3350         return uRef;
3351 }
3352
3353 static ULONG
3354 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER iface )
3355 {
3356         ULONG uRef;
3357         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3358
3359         EnterCriticalSection( &This->lock );
3360
3361         TRACE( "(%p) was 0x%08lx\n", This, This->ref );
3362         uRef = --(This->ref);
3363
3364         LeaveCriticalSection( &This->lock );
3365
3366         if ( uRef == 0 ) {
3367                 DeleteCriticalSection( &This->lock );
3368                 HeapFree( GetProcessHeap(), 0, This );
3369         }
3370
3371         return uRef;
3372 }
3373
3374 static HRESULT
3375 IDirectSoundCaptureBufferImpl_GetCaps(
3376         LPDIRECTSOUNDCAPTUREBUFFER iface,
3377         LPDSCBCAPS lpDSCBCaps )
3378 {
3379         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3380
3381         FIXME( "(%p)->(%p): stub\n", This, lpDSCBCaps );
3382
3383         return DS_OK;
3384 }
3385
3386 static HRESULT
3387 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
3388         LPDIRECTSOUNDCAPTUREBUFFER iface,
3389         LPDWORD lpdwCapturePosition,
3390         LPDWORD lpdwReadPosition )
3391 {
3392         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3393
3394         FIXME( "(%p)->(%p,%p): stub\n", This, lpdwCapturePosition, lpdwReadPosition );
3395
3396         return DS_OK;
3397 }
3398
3399 static HRESULT
3400 IDirectSoundCaptureBufferImpl_GetFormat(
3401         LPDIRECTSOUNDCAPTUREBUFFER iface,
3402         LPWAVEFORMATEX lpwfxFormat, 
3403         DWORD dwSizeAllocated, 
3404         LPDWORD lpdwSizeWritten )
3405 {
3406         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3407
3408         FIXME( "(%p)->(%p,0x%08lx,%p): stub\n", This, lpwfxFormat, dwSizeAllocated, lpdwSizeWritten );
3409
3410         return DS_OK;
3411 }
3412
3413 static HRESULT
3414 IDirectSoundCaptureBufferImpl_GetStatus(
3415         LPDIRECTSOUNDCAPTUREBUFFER iface,
3416         LPDWORD lpdwStatus )
3417 {
3418         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3419
3420         FIXME( "(%p)->(%p): stub\n", This, lpdwStatus );
3421
3422         return DS_OK;
3423 }
3424
3425 static HRESULT
3426 IDirectSoundCaptureBufferImpl_Initialize(
3427         LPDIRECTSOUNDCAPTUREBUFFER iface,
3428         LPDIRECTSOUNDCAPTURE lpDSC, 
3429         LPCDSCBUFFERDESC lpcDSCBDesc )
3430 {
3431         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3432
3433         FIXME( "(%p)->(%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
3434
3435         return DS_OK;
3436 }
3437
3438 static HRESULT
3439 IDirectSoundCaptureBufferImpl_Lock(
3440         LPDIRECTSOUNDCAPTUREBUFFER iface,
3441         DWORD dwReadCusor, 
3442         DWORD dwReadBytes, 
3443         LPVOID* lplpvAudioPtr1, 
3444         LPDWORD lpdwAudioBytes1, 
3445         LPVOID* lplpvAudioPtr2, 
3446         LPDWORD lpdwAudioBytes2, 
3447         DWORD dwFlags )
3448 {
3449         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3450
3451         FIXME( "(%p)->(%08lu,%08lu,%p,%p,%p,%p,0x%08lx): stub\n", This, dwReadCusor, dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2, lpdwAudioBytes2, dwFlags );
3452
3453         return DS_OK;
3454 }
3455
3456 static HRESULT
3457 IDirectSoundCaptureBufferImpl_Start(
3458         LPDIRECTSOUNDCAPTUREBUFFER iface,
3459         DWORD dwFlags )
3460 {
3461         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3462
3463         FIXME( "(%p)->(0x%08lx): stub\n", This, dwFlags );
3464
3465         return DS_OK;
3466 }
3467
3468 static HRESULT
3469 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER iface )
3470 {
3471         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3472
3473         FIXME( "(%p): stub\n", This );
3474
3475         return DS_OK;
3476 }
3477
3478 static HRESULT
3479 IDirectSoundCaptureBufferImpl_Unlock(
3480         LPDIRECTSOUNDCAPTUREBUFFER iface,
3481         LPVOID lpvAudioPtr1, 
3482         DWORD dwAudioBytes1, 
3483         LPVOID lpvAudioPtr2, 
3484         DWORD dwAudioBytes2 )
3485 {
3486         ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3487
3488         FIXME( "(%p)->(%p,%08lu,%p,%08lu): stub\n", This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2 );
3489
3490         return DS_OK;
3491 }
3492
3493
3494 static ICOM_VTABLE(IDirectSoundCaptureBuffer) dscbvt =
3495 {
3496         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3497         /* IUnknown methods */
3498         IDirectSoundCaptureBufferImpl_QueryInterface,
3499         IDirectSoundCaptureBufferImpl_AddRef,
3500         IDirectSoundCaptureBufferImpl_Release,
3501
3502         /* IDirectSoundCaptureBuffer methods */
3503         IDirectSoundCaptureBufferImpl_GetCaps,
3504         IDirectSoundCaptureBufferImpl_GetCurrentPosition,
3505         IDirectSoundCaptureBufferImpl_GetFormat,
3506         IDirectSoundCaptureBufferImpl_GetStatus,
3507         IDirectSoundCaptureBufferImpl_Initialize,
3508         IDirectSoundCaptureBufferImpl_Lock,
3509         IDirectSoundCaptureBufferImpl_Start,
3510         IDirectSoundCaptureBufferImpl_Stop,
3511         IDirectSoundCaptureBufferImpl_Unlock
3512 };
3513
3514 /*******************************************************************************
3515  * DirectSound ClassFactory
3516  */
3517 typedef struct
3518 {
3519     /* IUnknown fields */
3520     ICOM_VFIELD(IClassFactory);
3521     DWORD                       ref;
3522 } IClassFactoryImpl;
3523
3524 static HRESULT WINAPI 
3525 DSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
3526         ICOM_THIS(IClassFactoryImpl,iface);
3527
3528         FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
3529         return E_NOINTERFACE;
3530 }
3531
3532 static ULONG WINAPI
3533 DSCF_AddRef(LPCLASSFACTORY iface) {
3534         ICOM_THIS(IClassFactoryImpl,iface);
3535         return ++(This->ref);
3536 }
3537
3538 static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface) {
3539         ICOM_THIS(IClassFactoryImpl,iface);
3540         /* static class, won't be  freed */
3541         return --(This->ref);
3542 }
3543
3544 static HRESULT WINAPI DSCF_CreateInstance(
3545         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
3546 ) {
3547         ICOM_THIS(IClassFactoryImpl,iface);
3548
3549         TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
3550         if ( IsEqualGUID( &IID_IDirectSound, riid ) ) {
3551                 /* FIXME: reuse already created dsound if present? */
3552                 return DirectSoundCreate(riid,(LPDIRECTSOUND*)ppobj,pOuter);
3553         }
3554         return E_NOINTERFACE;
3555 }
3556
3557 static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
3558         ICOM_THIS(IClassFactoryImpl,iface);
3559         FIXME("(%p)->(%d),stub!\n",This,dolock);
3560         return S_OK;
3561 }
3562
3563 static ICOM_VTABLE(IClassFactory) DSCF_Vtbl = {
3564         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3565         DSCF_QueryInterface,
3566         DSCF_AddRef,
3567         DSCF_Release,
3568         DSCF_CreateInstance,
3569         DSCF_LockServer
3570 };
3571 static IClassFactoryImpl DSOUND_CF = {&DSCF_Vtbl, 1 };
3572
3573 /*******************************************************************************
3574  * DllGetClassObject [DSOUND.4]
3575  * Retrieves class object from a DLL object
3576  *
3577  * NOTES
3578  *    Docs say returns STDAPI
3579  *
3580  * PARAMS
3581  *    rclsid [I] CLSID for the class object
3582  *    riid   [I] Reference to identifier of interface for class object
3583  *    ppv    [O] Address of variable to receive interface pointer for riid
3584  *
3585  * RETURNS
3586  *    Success: S_OK
3587  *    Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
3588  *             E_UNEXPECTED
3589  */
3590 DWORD WINAPI DSOUND_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv)
3591 {
3592     TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
3593     if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
3594         *ppv = (LPVOID)&DSOUND_CF;
3595         IClassFactory_AddRef((IClassFactory*)*ppv);
3596     return S_OK;
3597     }
3598
3599     FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
3600     return CLASS_E_CLASSNOTAVAILABLE;
3601 }
3602
3603
3604 /*******************************************************************************
3605  * DllCanUnloadNow [DSOUND.3]  Determines whether the DLL is in use.
3606  *
3607  * RETURNS
3608  *    Success: S_OK
3609  *    Failure: S_FALSE
3610  */
3611 DWORD WINAPI DSOUND_DllCanUnloadNow(void)
3612 {
3613     FIXME("(void): stub\n");
3614     return S_FALSE;
3615 }