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