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