Like the AUTORADIOBUTTON, the parent of a RADIOBUTTON style button
[wine] / dlls / dsound / dsound_main.c
1 /*                      DirectSound
2  * 
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998 Rob Riggs
5  */
6 /*
7  * Note: This file requires multithread ability. It is not possible to
8  * implement the stuff in a single thread anyway. And most DirectX apps
9  * require threading themselves.
10  *
11  * Most thread locking is complete. There may be a few race
12  * conditions still lurking.
13  *
14  * Tested with a Soundblaster clone, a Gravis UltraSound Classic,
15  * and a Turtle Beach Tropez+.
16  *
17  * TODO:
18  *      Implement DirectSoundCapture API
19  *      Implement SetCooperativeLevel properly (need to address focus issues)
20  *      Use wavetable synth for static buffers if available
21  *      Implement DirectSound3DBuffers (stubs in place)
22  *      Use hardware 3D support if available (OSS support may be needed first)
23  *      Add support for APIs other than OSS: ALSA (http://alsa.jcu.cz/)
24  *      and esound (http://www.gnome.org), for instance
25  *
26  * FIXME: Status needs updating.
27  *
28  * Status:
29  * - Wing Commander 4/W95:
30  *   The intromovie plays without problems. Nearly lipsynchron.
31  * - DiscWorld 2
32  *   The sound works, but noticeable chunks are left out (from the sound and
33  *   the animation). Don't know why yet.
34  * - Diablo:
35  *   Sound works, but slows down the movieplayer.
36  * - XvT: 
37  *   Doesn't sound yet.
38  * - Monkey Island 3:
39  *   The background sound of the startscreen works ;)
40  * - WingCommander Prophecy Demo:
41  *   Sound works for the intromovie.
42  * - Total Annihilation (1998/12/04):
43  *   Sound plays perfectly in the game, but the Smacker movies
44  *   (http://www.smacker.com/) play silently.
45  * - A-10 Cuba! Demo (1998/12/04):
46  *   Sound works properly (for some people).
47  * - dsstream.exe, from DirectX 5.2 SDK (1998/12/04):
48  *   Works properly, but requires "-dll -winmm".
49  * - dsshow.exe, from DirectX 5.2 SDK (1998/12/04):
50  *   Initializes the DLL properly with CoCreateInstance(), but the
51  *   FileOpen dialog box is broken - could not test properly
52  * - The Dilbert Desktop Game: works (SB16)
53  */
54
55 #include "config.h"
56 #include <assert.h>
57 #include <errno.h>
58 #include <stdio.h>
59 #include <sys/types.h>
60 #include <sys/time.h>
61 #include <sys/fcntl.h>
62 #include <unistd.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <math.h>       /* Insomnia - pow() function */
66 #include "dsound.h"
67 #include "windef.h"
68 #include "wingdi.h"
69 #include "winuser.h"
70 #include "winerror.h"
71 #include "wine/obj_base.h"
72 #include "thread.h"
73 #include "debugtools.h"
74
75 DEFAULT_DEBUG_CHANNEL(dsound);
76
77
78 /*****************************************************************************
79  * Predeclare the interface implementation structures
80  */
81 typedef struct IDirectSoundImpl IDirectSoundImpl;
82 typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl;
83 typedef struct IDirectSoundNotifyImpl IDirectSoundNotifyImpl;
84 typedef struct IDirectSound3DListenerImpl IDirectSound3DListenerImpl;
85 typedef struct IDirectSound3DBufferImpl IDirectSound3DBufferImpl;
86
87 /*****************************************************************************
88  * IDirectSound implementation structure
89  */
90 struct IDirectSoundImpl
91 {
92     /* IUnknown fields */
93     ICOM_VFIELD(IDirectSound);
94     DWORD                      ref;
95     /* IDirectSoundImpl fields */
96     DWORD                       priolevel;
97     int                         nrofbuffers;
98     IDirectSoundBufferImpl**    buffers;
99     IDirectSoundBufferImpl*     primary;
100     IDirectSound3DListenerImpl* listener;
101     WAVEFORMATEX                wfx; /* current main waveformat */
102     CRITICAL_SECTION            lock;
103 };
104
105 /*****************************************************************************
106  * IDirectSoundBuffer implementation structure
107  */
108 struct IDirectSoundBufferImpl
109 {
110     /* IUnknown fields */
111     ICOM_VFIELD(IDirectSoundBuffer);
112     DWORD                            ref;
113     /* IDirectSoundBufferImpl fields */
114     WAVEFORMATEX              wfx;
115     LPBYTE                    buffer;
116     IDirectSound3DBufferImpl* ds3db;
117     DWORD                     playflags,playing;
118     DWORD                     playpos,writepos,buflen;
119     DWORD                     nAvgBytesPerSec;
120     DWORD                     freq;
121     ULONG                     freqAdjust;
122     LONG                      volume,pan;
123     LONG                      lVolAdjust,rVolAdjust;
124     IDirectSoundBufferImpl*   parent;         /* for duplicates */
125     IDirectSoundImpl*         dsound;
126     DSBUFFERDESC              dsbd;
127     LPDSBPOSITIONNOTIFY       notifies;
128     int                       nrofnotifies;
129     CRITICAL_SECTION          lock;
130 };
131
132 /*****************************************************************************
133  * IDirectSoundNotify implementation structure
134  */
135 struct IDirectSoundNotifyImpl
136 {
137     /* IUnknown fields */
138     ICOM_VFIELD(IDirectSoundNotify);
139     DWORD                            ref;
140     /* IDirectSoundNotifyImpl fields */
141     IDirectSoundBufferImpl* dsb;
142 };
143
144 /*****************************************************************************
145  *  IDirectSound3DListener implementation structure
146  */
147 struct IDirectSound3DListenerImpl
148 {
149     /* IUnknown fields */
150     ICOM_VFIELD(IDirectSound3DListener);
151     DWORD                                ref;
152     /* IDirectSound3DListenerImpl fields */
153     IDirectSoundBufferImpl* dsb;
154     DS3DLISTENER            ds3dl;
155     CRITICAL_SECTION        lock;   
156 };
157
158 /*****************************************************************************
159  * IDirectSound3DBuffer implementation structure
160  */
161 struct IDirectSound3DBufferImpl
162 {
163     /* IUnknown fields */
164     ICOM_VFIELD(IDirectSound3DBuffer);
165     DWORD                              ref;
166     /* IDirectSound3DBufferImpl fields */
167     IDirectSoundBufferImpl* dsb;
168     DS3DBUFFER              ds3db;
169     LPBYTE                  buffer;
170     DWORD                   buflen;
171     CRITICAL_SECTION        lock;
172 };
173
174
175 #ifdef HAVE_OSS
176 # include <sys/ioctl.h>
177 # ifdef HAVE_MACHINE_SOUNDCARD_H
178 #  include <machine/soundcard.h>
179 # endif
180 # ifdef HAVE_SYS_SOUNDCARD_H
181 #  include <sys/soundcard.h>
182 # endif
183 # ifdef HAVE_SOUNDCARD_H
184 #  include <soundcard.h>
185 # endif
186
187 /* #define USE_DSOUND3D 1 */
188
189 #define DSOUND_FRAGLEN ((primarybuf->wfx.nAvgBytesPerSec >> 4) & ~3)
190 #define DSOUND_FREQSHIFT (14)
191
192 static int audiofd = -1;
193 static int audioOK = 0;
194
195 static IDirectSoundImpl*        dsound = NULL;
196
197 static IDirectSoundBufferImpl*  primarybuf = NULL;
198
199 static int DSOUND_setformat(LPWAVEFORMATEX wfex);
200 static void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len);
201 static void DSOUND_CloseAudio(void);
202
203 #endif
204
205 /*******************************************************************************
206  *              DirectSoundEnumerateA
207  */
208 HRESULT WINAPI DirectSoundEnumerateA(
209         LPDSENUMCALLBACKA enumcb,
210         LPVOID context)
211 {
212         TRACE("enumcb = %p, context = %p\n", enumcb, context);
213
214 #ifdef HAVE_OSS
215         if (enumcb != NULL)
216                 enumcb(NULL,"WINE DirectSound using Open Sound System",
217                     "sound",context);
218 #endif
219
220         return DS_OK;
221 }
222
223 #ifdef HAVE_OSS
224 static void _dump_DSBCAPS(DWORD xmask) {
225         struct {
226                 DWORD   mask;
227                 char    *name;
228         } flags[] = {
229 #define FE(x) { x, #x },
230                 FE(DSBCAPS_PRIMARYBUFFER)
231                 FE(DSBCAPS_STATIC)
232                 FE(DSBCAPS_LOCHARDWARE)
233                 FE(DSBCAPS_LOCSOFTWARE)
234                 FE(DSBCAPS_CTRLFREQUENCY)
235                 FE(DSBCAPS_CTRLPAN)
236                 FE(DSBCAPS_CTRLVOLUME)
237                 FE(DSBCAPS_CTRLDEFAULT)
238                 FE(DSBCAPS_CTRLALL)
239                 FE(DSBCAPS_STICKYFOCUS)
240                 FE(DSBCAPS_GETCURRENTPOSITION2)
241         };
242         int     i;
243
244         for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
245                 if ((flags[i].mask & xmask) == flags[i].mask)
246                         DPRINTF("%s ",flags[i].name);
247 }
248
249 /*******************************************************************************
250  *              IDirectSound3DBuffer
251  */
252
253 /* IUnknown methods */
254 static HRESULT WINAPI IDirectSound3DBufferImpl_QueryInterface(
255         LPDIRECTSOUND3DBUFFER iface, REFIID riid, LPVOID *ppobj)
256 {
257         ICOM_THIS(IDirectSound3DBufferImpl,iface);
258
259         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
260         return E_FAIL;
261 }
262         
263 static ULONG WINAPI IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface)
264 {
265         ICOM_THIS(IDirectSound3DBufferImpl,iface);
266         This->ref++;
267         return This->ref;
268 }
269
270 static ULONG WINAPI IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface)
271 {
272         ICOM_THIS(IDirectSound3DBufferImpl,iface);
273         if(--This->ref)
274                 return This->ref;
275
276         HeapFree(GetProcessHeap(),0,This->buffer);
277         HeapFree(GetProcessHeap(),0,This);
278
279         return S_OK;
280 }
281
282 /* IDirectSound3DBuffer methods */
283 static HRESULT WINAPI IDirectSound3DBufferImpl_GetAllParameters(
284         LPDIRECTSOUND3DBUFFER iface,
285         LPDS3DBUFFER lpDs3dBuffer)
286 {
287         FIXME("stub\n");
288         return DS_OK;
289 }
290
291 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeAngles(
292         LPDIRECTSOUND3DBUFFER iface,
293         LPDWORD lpdwInsideConeAngle,
294         LPDWORD lpdwOutsideConeAngle)
295 {
296         FIXME("stub\n");
297         return DS_OK;
298 }
299
300 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOrientation(
301         LPDIRECTSOUND3DBUFFER iface,
302         LPD3DVECTOR lpvConeOrientation)
303 {
304         FIXME("stub\n");
305         return DS_OK;
306 }
307
308 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOutsideVolume(
309         LPDIRECTSOUND3DBUFFER iface,
310         LPLONG lplConeOutsideVolume)
311 {
312         FIXME("stub\n");
313         return DS_OK;
314 }
315
316 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMaxDistance(
317         LPDIRECTSOUND3DBUFFER iface,
318         LPD3DVALUE lpfMaxDistance)
319 {
320         FIXME("stub\n");
321         return DS_OK;
322 }
323
324 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMinDistance(
325         LPDIRECTSOUND3DBUFFER iface,
326         LPD3DVALUE lpfMinDistance)
327 {
328         FIXME("stub\n");
329         return DS_OK;
330 }
331
332 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMode(
333         LPDIRECTSOUND3DBUFFER iface,
334         LPDWORD lpdwMode)
335 {
336         FIXME("stub\n");
337         return DS_OK;
338 }
339
340 static HRESULT WINAPI IDirectSound3DBufferImpl_GetPosition(
341         LPDIRECTSOUND3DBUFFER iface,
342         LPD3DVECTOR lpvPosition)
343 {
344         FIXME("stub\n");
345         return DS_OK;
346 }
347
348 static HRESULT WINAPI IDirectSound3DBufferImpl_GetVelocity(
349         LPDIRECTSOUND3DBUFFER iface,
350         LPD3DVECTOR lpvVelocity)
351 {
352         FIXME("stub\n");
353         return DS_OK;
354 }
355
356 static HRESULT WINAPI IDirectSound3DBufferImpl_SetAllParameters(
357         LPDIRECTSOUND3DBUFFER iface,
358         LPCDS3DBUFFER lpcDs3dBuffer,
359         DWORD dwApply)
360 {
361         FIXME("stub\n");
362         return DS_OK;
363 }
364
365 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeAngles(
366         LPDIRECTSOUND3DBUFFER iface,
367         DWORD dwInsideConeAngle,
368         DWORD dwOutsideConeAngle,
369         DWORD dwApply)
370 {
371         FIXME("stub\n");
372         return DS_OK;
373 }
374
375 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOrientation(
376         LPDIRECTSOUND3DBUFFER iface,
377         D3DVALUE x, D3DVALUE y, D3DVALUE z,
378         DWORD dwApply)
379 {
380         FIXME("stub\n");
381         return DS_OK;
382 }
383
384 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOutsideVolume(
385         LPDIRECTSOUND3DBUFFER iface,
386         LONG lConeOutsideVolume,
387         DWORD dwApply)
388 {
389         FIXME("stub\n");
390         return DS_OK;
391 }
392
393 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMaxDistance(
394         LPDIRECTSOUND3DBUFFER iface,
395         D3DVALUE fMaxDistance,
396         DWORD dwApply)
397 {
398         FIXME("stub\n");
399         return DS_OK;
400 }
401
402 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMinDistance(
403         LPDIRECTSOUND3DBUFFER iface,
404         D3DVALUE fMinDistance,
405         DWORD dwApply)
406 {
407         FIXME("stub\n");
408         return DS_OK;
409 }
410
411 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMode(
412         LPDIRECTSOUND3DBUFFER iface,
413         DWORD dwMode,
414         DWORD dwApply)
415 {
416         ICOM_THIS(IDirectSound3DBufferImpl,iface);
417         TRACE("mode = %lx\n", dwMode);
418         This->ds3db.dwMode = dwMode;
419         return DS_OK;
420 }
421
422 static HRESULT WINAPI IDirectSound3DBufferImpl_SetPosition(
423         LPDIRECTSOUND3DBUFFER iface,
424         D3DVALUE x, D3DVALUE y, D3DVALUE z,
425         DWORD dwApply)
426 {
427         FIXME("stub\n");
428         return DS_OK;
429 }
430
431 static HRESULT WINAPI IDirectSound3DBufferImpl_SetVelocity(
432         LPDIRECTSOUND3DBUFFER iface,
433         D3DVALUE x, D3DVALUE y, D3DVALUE z,
434         DWORD dwApply)
435 {
436         FIXME("stub\n");
437         return DS_OK;
438 }
439
440 ICOM_VTABLE(IDirectSound3DBuffer) ds3dbvt = 
441 {
442         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
443         /* IUnknown methods */
444         IDirectSound3DBufferImpl_QueryInterface,
445         IDirectSound3DBufferImpl_AddRef,
446         IDirectSound3DBufferImpl_Release,
447         /* IDirectSound3DBuffer methods */
448         IDirectSound3DBufferImpl_GetAllParameters,
449         IDirectSound3DBufferImpl_GetConeAngles,
450         IDirectSound3DBufferImpl_GetConeOrientation,
451         IDirectSound3DBufferImpl_GetConeOutsideVolume,
452         IDirectSound3DBufferImpl_GetMaxDistance,
453         IDirectSound3DBufferImpl_GetMinDistance,
454         IDirectSound3DBufferImpl_GetMode,
455         IDirectSound3DBufferImpl_GetPosition,
456         IDirectSound3DBufferImpl_GetVelocity,
457         IDirectSound3DBufferImpl_SetAllParameters,
458         IDirectSound3DBufferImpl_SetConeAngles,
459         IDirectSound3DBufferImpl_SetConeOrientation,
460         IDirectSound3DBufferImpl_SetConeOutsideVolume,
461         IDirectSound3DBufferImpl_SetMaxDistance,
462         IDirectSound3DBufferImpl_SetMinDistance,
463         IDirectSound3DBufferImpl_SetMode,
464         IDirectSound3DBufferImpl_SetPosition,
465         IDirectSound3DBufferImpl_SetVelocity,
466 };
467
468 #ifdef USE_DSOUND3D
469 static int DSOUND_Create3DBuffer(IDirectSoundBufferImpl* dsb)
470 {
471         DWORD   i, temp, iSize, oSize, offset;
472         LPBYTE  bIbuf, bObuf, bTbuf = NULL;
473         LPWORD  wIbuf, wObuf, wTbuf = NULL;
474
475         /* Inside DirectX says it's stupid but allowed */
476         if (dsb->wfx.nChannels == 2) {
477                 /* Convert to mono */
478                 if (dsb->wfx.wBitsPerSample == 16) {
479                         iSize = dsb->buflen / 4;
480                         wTbuf = malloc(dsb->buflen / 2);
481                         if (wTbuf == NULL)
482                                 return DSERR_OUTOFMEMORY;
483                         for (i = 0; i < iSize; i++)
484                                 wTbuf[i] = (dsb->buffer[i] + dsb->buffer[(i * 2) + 1]) / 2;
485                         wIbuf = wTbuf;
486                 } else {
487                         iSize = dsb->buflen / 2;
488                         bTbuf = malloc(dsb->buflen / 2);
489                         if (bTbuf == NULL)
490                                 return DSERR_OUTOFMEMORY;
491                         for (i = 0; i < iSize; i++)
492                                 bTbuf[i] = (dsb->buffer[i] + dsb->buffer[(i * 2) + 1]) / 2;
493                         bIbuf = bTbuf;
494                 }
495         } else {
496                 if (dsb->wfx.wBitsPerSample == 16) {
497                         iSize = dsb->buflen / 2;
498                         wIbuf = (LPWORD) dsb->buffer;
499                 } else {
500                         bIbuf = (LPBYTE) dsb->buffer;
501                         iSize = dsb->buflen;
502                 }
503         }
504
505         if (primarybuf->wfx.wBitsPerSample == 16) {
506                 wObuf = (LPWORD) dsb->ds3db->buffer;
507                 oSize = dsb->ds3db->buflen / 2;
508         } else {
509                 bObuf = (LPBYTE) dsb->ds3db->buffer;
510                 oSize = dsb->ds3db->buflen;
511         }
512
513         offset = primarybuf->wfx.nSamplesPerSec / 100;          /* 10ms */
514         if (primarybuf->wfx.wBitsPerSample == 16 && dsb->wfx.wBitsPerSample == 16)
515                 for (i = 0; i < iSize; i++) {
516                         temp = wIbuf[i];
517                         if (i >= offset)
518                                 temp += wIbuf[i - offset] >> 9;
519                         else
520                                 temp += wIbuf[i + iSize - offset] >> 9;
521                         wObuf[i * 2] = temp;
522                         wObuf[(i * 2) + 1] = temp;
523                 }
524         else if (primarybuf->wfx.wBitsPerSample == 8 && dsb->wfx.wBitsPerSample == 8)
525                 for (i = 0; i < iSize; i++) {
526                         temp = bIbuf[i];
527                         if (i >= offset)
528                                 temp += bIbuf[i - offset] >> 5;
529                         else
530                                 temp += bIbuf[i + iSize - offset] >> 5;
531                         bObuf[i * 2] = temp;
532                         bObuf[(i * 2) + 1] = temp;
533                 }
534         
535         if (wTbuf)
536                 free(wTbuf);
537         if (bTbuf)
538                 free(bTbuf);
539
540         return DS_OK;
541 }
542 #endif
543 /*******************************************************************************
544  *              IDirectSound3DListener
545  */
546
547 /* IUnknown methods */
548 static HRESULT WINAPI IDirectSound3DListenerImpl_QueryInterface(
549         LPDIRECTSOUND3DLISTENER iface, REFIID riid, LPVOID *ppobj)
550 {
551         ICOM_THIS(IDirectSound3DListenerImpl,iface);
552
553         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
554         return E_FAIL;
555 }
556         
557 static ULONG WINAPI IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface)
558 {
559         ICOM_THIS(IDirectSound3DListenerImpl,iface);
560         This->ref++;
561         return This->ref;
562 }
563
564 static ULONG WINAPI IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface)
565 {
566         ICOM_THIS(IDirectSound3DListenerImpl,iface);
567         This->ref--;
568         return This->ref;
569 }
570
571 /* IDirectSound3DListener methods */
572 static HRESULT WINAPI IDirectSound3DListenerImpl_GetAllParameter(
573         LPDIRECTSOUND3DLISTENER iface,
574         LPDS3DLISTENER lpDS3DL)
575 {
576         FIXME("stub\n");
577         return DS_OK;
578 }
579
580 static HRESULT WINAPI IDirectSound3DListenerImpl_GetDistanceFactor(
581         LPDIRECTSOUND3DLISTENER iface,
582         LPD3DVALUE lpfDistanceFactor)
583 {
584         FIXME("stub\n");
585         return DS_OK;
586 }
587
588 static HRESULT WINAPI IDirectSound3DListenerImpl_GetDopplerFactor(
589         LPDIRECTSOUND3DLISTENER iface,
590         LPD3DVALUE lpfDopplerFactor)
591 {
592         FIXME("stub\n");
593         return DS_OK;
594 }
595
596 static HRESULT WINAPI IDirectSound3DListenerImpl_GetOrientation(
597         LPDIRECTSOUND3DLISTENER iface,
598         LPD3DVECTOR lpvOrientFront,
599         LPD3DVECTOR lpvOrientTop)
600 {
601         FIXME("stub\n");
602         return DS_OK;
603 }
604
605 static HRESULT WINAPI IDirectSound3DListenerImpl_GetPosition(
606         LPDIRECTSOUND3DLISTENER iface,
607         LPD3DVECTOR lpvPosition)
608 {
609         FIXME("stub\n");
610         return DS_OK;
611 }
612
613 static HRESULT WINAPI IDirectSound3DListenerImpl_GetRolloffFactor(
614         LPDIRECTSOUND3DLISTENER iface,
615         LPD3DVALUE lpfRolloffFactor)
616 {
617         FIXME("stub\n");
618         return DS_OK;
619 }
620
621 static HRESULT WINAPI IDirectSound3DListenerImpl_GetVelocity(
622         LPDIRECTSOUND3DLISTENER iface,
623         LPD3DVECTOR lpvVelocity)
624 {
625         FIXME("stub\n");
626         return DS_OK;
627 }
628
629 static HRESULT WINAPI IDirectSound3DListenerImpl_SetAllParameters(
630         LPDIRECTSOUND3DLISTENER iface,
631         LPCDS3DLISTENER lpcDS3DL,
632         DWORD dwApply)
633 {
634         FIXME("stub\n");
635         return DS_OK;
636 }
637
638 static HRESULT WINAPI IDirectSound3DListenerImpl_SetDistanceFactor(
639         LPDIRECTSOUND3DLISTENER iface,
640         D3DVALUE fDistanceFactor,
641         DWORD dwApply)
642 {
643         FIXME("stub\n");
644         return DS_OK;
645 }
646
647 static HRESULT WINAPI IDirectSound3DListenerImpl_SetDopplerFactor(
648         LPDIRECTSOUND3DLISTENER iface,
649         D3DVALUE fDopplerFactor,
650         DWORD dwApply)
651 {
652         FIXME("stub\n");
653         return DS_OK;
654 }
655
656 static HRESULT WINAPI IDirectSound3DListenerImpl_SetOrientation(
657         LPDIRECTSOUND3DLISTENER iface,
658         D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront,
659         D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop,
660         DWORD dwApply)
661 {
662         FIXME("stub\n");
663         return DS_OK;
664 }
665
666 static HRESULT WINAPI IDirectSound3DListenerImpl_SetPosition(
667         LPDIRECTSOUND3DLISTENER iface,
668         D3DVALUE x, D3DVALUE y, D3DVALUE z,
669         DWORD dwApply)
670 {
671         FIXME("stub\n");
672         return DS_OK;
673 }
674
675 static HRESULT WINAPI IDirectSound3DListenerImpl_SetRolloffFactor(
676         LPDIRECTSOUND3DLISTENER iface,
677         D3DVALUE fRolloffFactor,
678         DWORD dwApply)
679 {
680         FIXME("stub\n");
681         return DS_OK;
682 }
683
684 static HRESULT WINAPI IDirectSound3DListenerImpl_SetVelocity(
685         LPDIRECTSOUND3DLISTENER iface,
686         D3DVALUE x, D3DVALUE y, D3DVALUE z,
687         DWORD dwApply)
688 {
689         FIXME("stub\n");
690         return DS_OK;
691 }
692
693 static HRESULT WINAPI IDirectSound3DListenerImpl_CommitDeferredSettings(
694         LPDIRECTSOUND3DLISTENER iface)
695
696 {
697         FIXME("stub\n");
698         return DS_OK;
699 }
700
701 ICOM_VTABLE(IDirectSound3DListener) ds3dlvt = 
702 {
703         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
704         /* IUnknown methods */
705         IDirectSound3DListenerImpl_QueryInterface,
706         IDirectSound3DListenerImpl_AddRef,
707         IDirectSound3DListenerImpl_Release,
708         /* IDirectSound3DListener methods */
709         IDirectSound3DListenerImpl_GetAllParameter,
710         IDirectSound3DListenerImpl_GetDistanceFactor,
711         IDirectSound3DListenerImpl_GetDopplerFactor,
712         IDirectSound3DListenerImpl_GetOrientation,
713         IDirectSound3DListenerImpl_GetPosition,
714         IDirectSound3DListenerImpl_GetRolloffFactor,
715         IDirectSound3DListenerImpl_GetVelocity,
716         IDirectSound3DListenerImpl_SetAllParameters,
717         IDirectSound3DListenerImpl_SetDistanceFactor,
718         IDirectSound3DListenerImpl_SetDopplerFactor,
719         IDirectSound3DListenerImpl_SetOrientation,
720         IDirectSound3DListenerImpl_SetPosition,
721         IDirectSound3DListenerImpl_SetRolloffFactor,
722         IDirectSound3DListenerImpl_SetVelocity,
723         IDirectSound3DListenerImpl_CommitDeferredSettings,
724 };
725
726 /*******************************************************************************
727  *              IDirectSoundNotify
728  */
729 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(
730         LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj
731 ) {
732         ICOM_THIS(IDirectSoundNotifyImpl,iface);
733
734         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
735         return E_FAIL;
736 }
737
738 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface) {
739         ICOM_THIS(IDirectSoundNotifyImpl,iface);
740         return ++(This->ref);
741 }
742
743 static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface) {
744         ICOM_THIS(IDirectSoundNotifyImpl,iface);
745         This->ref--;
746         if (!This->ref) {
747                 IDirectSoundNotify_Release((LPDIRECTSOUNDBUFFER)This->dsb);
748                 HeapFree(GetProcessHeap(),0,This);
749                 return S_OK;
750         }
751         return This->ref;
752 }
753
754 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
755         LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
756 ) {
757         ICOM_THIS(IDirectSoundNotifyImpl,iface);
758         int     i;
759
760         if (TRACE_ON(dsound)) {
761             TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
762             for (i=0;i<howmuch;i++)
763                     TRACE("notify at %ld to 0x%08lx\n",
764                             notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
765         }
766         This->dsb->notifies = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->dsb->notifies,(This->dsb->nrofnotifies+howmuch)*sizeof(DSBPOSITIONNOTIFY));
767         memcpy( This->dsb->notifies+This->dsb->nrofnotifies,
768                 notify,
769                 howmuch*sizeof(DSBPOSITIONNOTIFY)
770         );
771         This->dsb->nrofnotifies+=howmuch;
772
773         return S_OK;
774 }
775
776 ICOM_VTABLE(IDirectSoundNotify) dsnvt = 
777 {
778         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
779         IDirectSoundNotifyImpl_QueryInterface,
780         IDirectSoundNotifyImpl_AddRef,
781         IDirectSoundNotifyImpl_Release,
782         IDirectSoundNotifyImpl_SetNotificationPositions,
783 };
784
785 /*******************************************************************************
786  *              IDirectSoundBuffer
787  */
788
789 /* This sets this format for the <em>Primary Buffer Only</em> */
790 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
791 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
792         LPDIRECTSOUNDBUFFER iface,LPWAVEFORMATEX wfex
793 ) {
794         ICOM_THIS(IDirectSoundBufferImpl,iface);
795         IDirectSoundBufferImpl** dsb;
796         int                     i;
797
798         /* Let's be pedantic! */
799         if ((wfex == NULL) ||
800             (wfex->wFormatTag != WAVE_FORMAT_PCM) ||
801             (wfex->nChannels < 1) || (wfex->nChannels > 2) ||
802             (wfex->nSamplesPerSec < 1) ||
803             (wfex->nBlockAlign < 1) || (wfex->nChannels > 4) ||
804             ((wfex->wBitsPerSample != 8) && (wfex->wBitsPerSample != 16))) {
805                 TRACE("failed pedantic check!\n");
806                 return DSERR_INVALIDPARAM;
807         }
808
809         /* **** */
810         EnterCriticalSection(&(This->dsound->lock));
811
812         if (primarybuf->wfx.nSamplesPerSec != wfex->nSamplesPerSec) {
813                 dsb = dsound->buffers;
814                 for (i = 0; i < dsound->nrofbuffers; i++, dsb++) {
815                         /* **** */
816                         EnterCriticalSection(&((*dsb)->lock));
817
818                         (*dsb)->freqAdjust = ((*dsb)->freq << DSOUND_FREQSHIFT) /
819                                 wfex->nSamplesPerSec;
820
821                         LeaveCriticalSection(&((*dsb)->lock));
822                         /* **** */
823                 }
824         }
825
826         memcpy(&(primarybuf->wfx), wfex, sizeof(primarybuf->wfx));
827
828         TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld"
829                    "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
830                    wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
831                    wfex->nAvgBytesPerSec, wfex->nBlockAlign, 
832                    wfex->wBitsPerSample, wfex->cbSize);
833
834         primarybuf->wfx.nAvgBytesPerSec =
835                 This->wfx.nSamplesPerSec * This->wfx.nBlockAlign;
836         DSOUND_CloseAudio();
837
838         LeaveCriticalSection(&(This->dsound->lock));
839         /* **** */
840
841         return DS_OK;
842 }
843
844 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
845         LPDIRECTSOUNDBUFFER iface,LONG vol
846 ) {
847         ICOM_THIS(IDirectSoundBufferImpl,iface);
848         double  temp;
849
850         TRACE("(%p,%ld)\n",This,vol);
851
852         /* I'm not sure if we need this for primary buffer */
853         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME))
854                 return DSERR_CONTROLUNAVAIL;
855
856         if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN))
857                 return DSERR_INVALIDPARAM;
858
859         /* This needs to adjust the soundcard volume when */
860         /* called for the primary buffer */
861         if (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) {
862                 FIXME("Volume control of primary unimplemented.\n");
863                 This->volume = vol;
864                 return DS_OK;
865         }
866
867         /* **** */
868         EnterCriticalSection(&(This->lock));
869
870         This->volume = vol;
871
872         temp = (double) (This->volume - (This->pan > 0 ? This->pan : 0));
873         This->lVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 32768.0);
874         temp = (double) (This->volume + (This->pan < 0 ? This->pan : 0));
875         This->rVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 32768.0);
876
877         LeaveCriticalSection(&(This->lock));
878         /* **** */
879
880         TRACE("left = %lx, right = %lx\n", This->lVolAdjust, This->rVolAdjust);
881
882         return DS_OK;
883 }
884
885 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(
886         LPDIRECTSOUNDBUFFER iface,LPLONG vol
887 ) {
888         ICOM_THIS(IDirectSoundBufferImpl,iface);
889         TRACE("(%p,%p)\n",This,vol);
890
891         if (vol == NULL)
892                 return DSERR_INVALIDPARAM;
893
894         *vol = This->volume;
895         return DS_OK;
896 }
897
898 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
899         LPDIRECTSOUNDBUFFER iface,DWORD freq
900 ) {
901         ICOM_THIS(IDirectSoundBufferImpl,iface);
902         TRACE("(%p,%ld)\n",This,freq);
903
904         /* You cannot set the frequency of the primary buffer */
905         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY) ||
906             (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER))
907                 return DSERR_CONTROLUNAVAIL;
908
909         if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX))
910                 return DSERR_INVALIDPARAM;
911
912         /* **** */
913         EnterCriticalSection(&(This->lock));
914
915         This->freq = freq;
916         This->freqAdjust = (freq << DSOUND_FREQSHIFT) / primarybuf->wfx.nSamplesPerSec;
917         This->nAvgBytesPerSec = freq * This->wfx.nBlockAlign;
918
919         LeaveCriticalSection(&(This->lock));
920         /* **** */
921
922         return DS_OK;
923 }
924
925 static HRESULT WINAPI IDirectSoundBufferImpl_Play(
926         LPDIRECTSOUNDBUFFER iface,DWORD reserved1,DWORD reserved2,DWORD flags
927 ) {
928         ICOM_THIS(IDirectSoundBufferImpl,iface);
929         TRACE("(%p,%08lx,%08lx,%08lx)\n",
930                 This,reserved1,reserved2,flags
931         );
932         This->playflags = flags;
933         This->playing = 1;
934         return DS_OK;
935 }
936
937 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER iface)
938 {
939         ICOM_THIS(IDirectSoundBufferImpl,iface);
940         TRACE("(%p)\n",This);
941
942         /* **** */
943         EnterCriticalSection(&(This->lock));
944
945         This->playing = 0;
946         DSOUND_CheckEvent(This, 0);
947
948         LeaveCriticalSection(&(This->lock));
949         /* **** */
950
951         return DS_OK;
952 }
953
954 static DWORD WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER iface) {
955         ICOM_THIS(IDirectSoundBufferImpl,iface);
956 /*      TRACE("(%p) ref was %ld\n",This, This->ref); */
957
958         return ++(This->ref);
959 }
960 static DWORD WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER iface) {
961         ICOM_THIS(IDirectSoundBufferImpl,iface);
962         int     i;
963
964 /*      TRACE("(%p) ref was %ld\n",This, This->ref); */
965
966         if (--This->ref)
967                 return This->ref;
968
969         EnterCriticalSection(&(This->dsound->lock));
970         for (i=0;i<This->dsound->nrofbuffers;i++)
971                 if (This->dsound->buffers[i] == This)
972                         break;
973         if (i < This->dsound->nrofbuffers) {
974                 /* Put the last buffer of the list in the (now empty) position */
975                 This->dsound->buffers[i] = This->dsound->buffers[This->dsound->nrofbuffers - 1];
976                 This->dsound->buffers = HeapReAlloc(GetProcessHeap(),0,This->dsound->buffers,sizeof(LPDIRECTSOUNDBUFFER)*This->dsound->nrofbuffers);
977                 This->dsound->nrofbuffers--;
978                 IDirectSound_Release((LPDIRECTSOUND)This->dsound);
979         }
980         LeaveCriticalSection(&(This->dsound->lock));
981
982         DeleteCriticalSection(&(This->lock));
983         if (This->ds3db && ICOM_VTBL(This->ds3db))
984                 IDirectSound3DBuffer_Release((LPDIRECTSOUND3DBUFFER)This->ds3db);
985         if (This->parent)
986                 /* this is a duplicate buffer */
987                 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->parent);
988         else
989                 /* this is a toplevel buffer */
990                 HeapFree(GetProcessHeap(),0,This->buffer);
991
992         HeapFree(GetProcessHeap(),0,This);
993         
994         if (This == primarybuf)
995                 primarybuf = NULL;
996
997         return DS_OK;
998 }
999
1000 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
1001         LPDIRECTSOUNDBUFFER iface,LPDWORD playpos,LPDWORD writepos
1002 ) {
1003         ICOM_THIS(IDirectSoundBufferImpl,iface);
1004         TRACE("(%p,%p,%p)\n",This,playpos,writepos);
1005         if (playpos) *playpos = This->playpos;
1006         if (writepos) *writepos = This->writepos;
1007         TRACE("playpos = %ld, writepos = %ld\n", playpos?*playpos:0, writepos?*writepos:0);
1008         return DS_OK;
1009 }
1010
1011 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
1012         LPDIRECTSOUNDBUFFER iface,LPDWORD status
1013 ) {
1014         ICOM_THIS(IDirectSoundBufferImpl,iface);
1015         TRACE("(%p,%p)\n",This,status);
1016
1017         if (status == NULL)
1018                 return DSERR_INVALIDPARAM;
1019
1020         *status = 0;
1021         if (This->playing)
1022                 *status |= DSBSTATUS_PLAYING;
1023         if (This->playflags & DSBPLAY_LOOPING)
1024                 *status |= DSBSTATUS_LOOPING;
1025
1026         return DS_OK;
1027 }
1028
1029
1030 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
1031         LPDIRECTSOUNDBUFFER iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten
1032 ) {
1033         ICOM_THIS(IDirectSoundBufferImpl,iface);
1034         TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
1035
1036         if (wfsize>sizeof(This->wfx))
1037                 wfsize = sizeof(This->wfx);
1038         if (lpwf) {     /* NULL is valid */
1039                 memcpy(lpwf,&(This->wfx),wfsize);
1040                 if (wfwritten)
1041                         *wfwritten = wfsize;
1042         } else
1043                 if (wfwritten)
1044                         *wfwritten = sizeof(This->wfx);
1045                 else
1046                         return DSERR_INVALIDPARAM;
1047
1048         return DS_OK;
1049 }
1050
1051 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
1052         LPDIRECTSOUNDBUFFER iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
1053 ) {
1054         ICOM_THIS(IDirectSoundBufferImpl,iface);
1055
1056         TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1057                 This,
1058                 writecursor,
1059                 writebytes,
1060                 lplpaudioptr1,
1061                 audiobytes1,
1062                 lplpaudioptr2,
1063                 audiobytes2,
1064                 flags
1065         );
1066         if (flags & DSBLOCK_FROMWRITECURSOR)
1067                 writecursor += This->writepos;
1068         if (flags & DSBLOCK_ENTIREBUFFER)
1069                 writebytes = This->buflen;
1070         if (writebytes > This->buflen)
1071                 writebytes = This->buflen;
1072
1073         assert(audiobytes1!=audiobytes2);
1074         assert(lplpaudioptr1!=lplpaudioptr2);
1075         if (writecursor+writebytes <= This->buflen) {
1076                 *(LPBYTE*)lplpaudioptr1 = This->buffer+writecursor;
1077                 *audiobytes1 = writebytes;
1078                 if (lplpaudioptr2)
1079                         *(LPBYTE*)lplpaudioptr2 = NULL;
1080                 if (audiobytes2)
1081                         *audiobytes2 = 0;
1082                 TRACE("->%ld.0\n",writebytes);
1083         } else {
1084                 *(LPBYTE*)lplpaudioptr1 = This->buffer+writecursor;
1085                 *audiobytes1 = This->buflen-writecursor;
1086                 if (lplpaudioptr2)
1087                         *(LPBYTE*)lplpaudioptr2 = This->buffer;
1088                 if (audiobytes2)
1089                         *audiobytes2 = writebytes-(This->buflen-writecursor);
1090                 TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
1091         }
1092         /* No. See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 21 */
1093         /* This->writepos=(writecursor+writebytes)%This->buflen; */
1094         return DS_OK;
1095 }
1096
1097 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
1098         LPDIRECTSOUNDBUFFER iface,DWORD newpos
1099 ) {
1100         ICOM_THIS(IDirectSoundBufferImpl,iface);
1101         TRACE("(%p,%ld)\n",This,newpos);
1102
1103         /* **** */
1104         EnterCriticalSection(&(This->lock));
1105
1106         This->playpos = newpos;
1107
1108         LeaveCriticalSection(&(This->lock));
1109         /* **** */
1110
1111         return DS_OK;
1112 }
1113
1114 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
1115         LPDIRECTSOUNDBUFFER iface,LONG pan
1116 ) {
1117         ICOM_THIS(IDirectSoundBufferImpl,iface);
1118         double  temp;
1119
1120         TRACE("(%p,%ld)\n",This,pan);
1121
1122         if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT))
1123                 return DSERR_INVALIDPARAM;
1124
1125         /* You cannot set the pan of the primary buffer */
1126         /* and you cannot use both pan and 3D controls */
1127         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
1128             (This->dsbd.dwFlags & DSBCAPS_CTRL3D) ||
1129             (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER))
1130                 return DSERR_CONTROLUNAVAIL;
1131
1132         /* **** */
1133         EnterCriticalSection(&(This->lock));
1134
1135         This->pan = pan;
1136         
1137         temp = (double) (This->volume - (This->pan > 0 ? This->pan : 0));
1138         This->lVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 32768.0);
1139         temp = (double) (This->volume + (This->pan < 0 ? This->pan : 0));
1140         This->rVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 32768.0);
1141
1142         LeaveCriticalSection(&(This->lock));
1143         /* **** */
1144
1145         return DS_OK;
1146 }
1147
1148 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
1149         LPDIRECTSOUNDBUFFER iface,LPLONG pan
1150 ) {
1151         ICOM_THIS(IDirectSoundBufferImpl,iface);
1152         TRACE("(%p,%p)\n",This,pan);
1153
1154         if (pan == NULL)
1155                 return DSERR_INVALIDPARAM;
1156
1157         *pan = This->pan;
1158
1159         return DS_OK;
1160 }
1161
1162 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
1163         LPDIRECTSOUNDBUFFER iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
1164 ) {
1165         ICOM_THIS(IDirectSoundBufferImpl,iface);
1166         TRACE("(%p,%p,%ld,%p,%ld):stub\n", This,p1,x1,p2,x2);
1167
1168         /* There is really nothing to do here. Should someone */
1169         /* choose to implement static buffers in hardware (by */
1170         /* using a wave table synth, for example) this is where */
1171         /* you'd want to do the loading. For software buffers, */
1172         /* which is what we currently use, we need do nothing. */
1173
1174 #if 0
1175         /* It's also the place to pre-process 3D buffers... */
1176         
1177         /* This is highly experimental and liable to break things */
1178         if (This->dsbd.dwFlags & DSBCAPS_CTRL3D)
1179                 DSOUND_Create3DBuffer(This);
1180 #endif
1181
1182         return DS_OK;
1183 }
1184
1185 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
1186         LPDIRECTSOUNDBUFFER iface,LPDWORD freq
1187 ) {
1188         ICOM_THIS(IDirectSoundBufferImpl,iface);
1189         TRACE("(%p,%p)\n",This,freq);
1190
1191         if (freq == NULL)
1192                 return DSERR_INVALIDPARAM;
1193
1194         *freq = This->freq;
1195         TRACE("-> %ld\n", *freq);
1196
1197         return DS_OK;
1198 }
1199
1200 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
1201         LPDIRECTSOUNDBUFFER iface,LPDIRECTSOUND dsound,LPDSBUFFERDESC dbsd
1202 ) {
1203         ICOM_THIS(IDirectSoundBufferImpl,iface);
1204         FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
1205         DPRINTF("Re-Init!!!\n");
1206         return DSERR_ALREADYINITIALIZED;
1207 }
1208
1209 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
1210         LPDIRECTSOUNDBUFFER iface,LPDSBCAPS caps
1211 ) {
1212         ICOM_THIS(IDirectSoundBufferImpl,iface);
1213         TRACE("(%p)->(%p)\n",This,caps);
1214   
1215         if (caps == NULL)
1216                 return DSERR_INVALIDPARAM;
1217
1218         /* I think we should check this value, not set it. See */
1219         /* Inside DirectX, p215. That should apply here, too. */
1220         caps->dwSize = sizeof(*caps);
1221
1222         caps->dwFlags = This->dsbd.dwFlags | DSBCAPS_LOCSOFTWARE;
1223         caps->dwBufferBytes = This->dsbd.dwBufferBytes;
1224         /* This value represents the speed of the "unlock" command.
1225            As unlock is quite fast (it does not do anything), I put
1226            4096 ko/s = 4 Mo / s */
1227         caps->dwUnlockTransferRate = 4096;
1228         caps->dwPlayCpuOverhead = 0;
1229         
1230         return DS_OK;
1231 }
1232
1233 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
1234         LPDIRECTSOUNDBUFFER iface,REFIID riid,LPVOID *ppobj
1235 ) {
1236         ICOM_THIS(IDirectSoundBufferImpl,iface);
1237
1238         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1239
1240         if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
1241                 IDirectSoundNotifyImpl  *dsn;
1242
1243                 dsn = (IDirectSoundNotifyImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn));
1244                 dsn->ref = 1;
1245                 dsn->dsb = This;
1246                 IDirectSoundBuffer_AddRef(iface);
1247                 ICOM_VTBL(dsn) = &dsnvt;
1248                 *ppobj = (LPVOID)dsn;
1249                 return S_OK;
1250         }
1251
1252         if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
1253                 *ppobj = This->ds3db;
1254                 if (*ppobj)
1255                         return DS_OK;
1256         }
1257
1258         return E_FAIL;
1259 }
1260
1261 static ICOM_VTABLE(IDirectSoundBuffer) dsbvt = 
1262 {
1263         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1264         IDirectSoundBufferImpl_QueryInterface,
1265         IDirectSoundBufferImpl_AddRef,
1266         IDirectSoundBufferImpl_Release,
1267         IDirectSoundBufferImpl_GetCaps,
1268         IDirectSoundBufferImpl_GetCurrentPosition,
1269         IDirectSoundBufferImpl_GetFormat,
1270         IDirectSoundBufferImpl_GetVolume,
1271         IDirectSoundBufferImpl_GetPan,
1272         IDirectSoundBufferImpl_GetFrequency,
1273         IDirectSoundBufferImpl_GetStatus,
1274         IDirectSoundBufferImpl_Initialize,
1275         IDirectSoundBufferImpl_Lock,
1276         IDirectSoundBufferImpl_Play,
1277         IDirectSoundBufferImpl_SetCurrentPosition,
1278         IDirectSoundBufferImpl_SetFormat,
1279         IDirectSoundBufferImpl_SetVolume,
1280         IDirectSoundBufferImpl_SetPan,
1281         IDirectSoundBufferImpl_SetFrequency,
1282         IDirectSoundBufferImpl_Stop,
1283         IDirectSoundBufferImpl_Unlock
1284 };
1285
1286 /*******************************************************************************
1287  *              IDirectSound
1288  */
1289
1290 static HRESULT WINAPI IDirectSoundImpl_SetCooperativeLevel(
1291         LPDIRECTSOUND iface,HWND hwnd,DWORD level
1292 ) {
1293         ICOM_THIS(IDirectSoundImpl,iface);
1294         FIXME("(%p,%08lx,%ld):stub\n",This,(DWORD)hwnd,level);
1295         return DS_OK;
1296 }
1297
1298 static HRESULT WINAPI IDirectSoundImpl_CreateSoundBuffer(
1299         LPDIRECTSOUND iface,LPDSBUFFERDESC dsbd,LPLPDIRECTSOUNDBUFFER ppdsb,LPUNKNOWN lpunk
1300 ) {
1301         ICOM_THIS(IDirectSoundImpl,iface);
1302         IDirectSoundBufferImpl** ippdsb=(IDirectSoundBufferImpl**)ppdsb;
1303         LPWAVEFORMATEX  wfex;
1304
1305         TRACE("(%p,%p,%p,%p)\n",This,dsbd,ippdsb,lpunk);
1306         
1307         if ((This == NULL) || (dsbd == NULL) || (ippdsb == NULL))
1308                 return DSERR_INVALIDPARAM;
1309         
1310         if (TRACE_ON(dsound)) {
1311                 TRACE("(structsize=%ld)\n",dsbd->dwSize);
1312                 TRACE("(flags=0x%08lx:\n",dsbd->dwFlags);
1313                 _dump_DSBCAPS(dsbd->dwFlags);
1314                 DPRINTF(")\n");
1315                 TRACE("(bufferbytes=%ld)\n",dsbd->dwBufferBytes);
1316                 TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
1317         }
1318
1319         wfex = dsbd->lpwfxFormat;
1320
1321         if (wfex)
1322                 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
1323                    "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1324                    wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
1325                    wfex->nAvgBytesPerSec, wfex->nBlockAlign, 
1326                    wfex->wBitsPerSample, wfex->cbSize);
1327
1328         if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1329                 if (primarybuf) {
1330                         IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)primarybuf);
1331                         *ippdsb = primarybuf;
1332                         primarybuf->dsbd.dwFlags = dsbd->dwFlags;
1333                         return DS_OK;
1334                 } /* Else create primarybuf */
1335         }
1336
1337         *ippdsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundBufferImpl));
1338         if (*ippdsb == NULL)
1339                 return DSERR_OUTOFMEMORY;
1340         (*ippdsb)->ref = 1;
1341
1342         TRACE("Created buffer at %p\n", *ippdsb);
1343
1344         if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1345                 (*ippdsb)->buflen = dsound->wfx.nAvgBytesPerSec;
1346                 (*ippdsb)->freq = dsound->wfx.nSamplesPerSec;
1347         } else {
1348                 (*ippdsb)->buflen = dsbd->dwBufferBytes;
1349                 (*ippdsb)->freq = dsbd->lpwfxFormat->nSamplesPerSec;
1350         }
1351         (*ippdsb)->buffer = (LPBYTE)HeapAlloc(GetProcessHeap(),0,(*ippdsb)->buflen);
1352         if ((*ippdsb)->buffer == NULL) {
1353                 HeapFree(GetProcessHeap(),0,(*ippdsb));
1354                 *ippdsb = NULL;
1355                 return DSERR_OUTOFMEMORY;
1356         }
1357         /* It's not necessary to initialize values to zero since */
1358         /* we allocated this structure with HEAP_ZERO_MEMORY... */
1359         (*ippdsb)->playpos = 0;
1360         (*ippdsb)->writepos = 0;
1361         (*ippdsb)->parent = NULL;
1362         ICOM_VTBL(*ippdsb) = &dsbvt;
1363         (*ippdsb)->dsound = This;
1364         (*ippdsb)->playing = 0;
1365         (*ippdsb)->lVolAdjust = (1 << 15);
1366         (*ippdsb)->rVolAdjust = (1 << 15);
1367
1368         if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1369                 (*ippdsb)->freqAdjust = ((*ippdsb)->freq << DSOUND_FREQSHIFT) /
1370                         primarybuf->wfx.nSamplesPerSec;
1371                 (*ippdsb)->nAvgBytesPerSec = (*ippdsb)->freq *
1372                         dsbd->lpwfxFormat->nBlockAlign;
1373         }
1374
1375         memcpy(&((*ippdsb)->dsbd),dsbd,sizeof(*dsbd));
1376
1377         EnterCriticalSection(&(This->lock));
1378         /* register buffer */
1379         if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1380                 This->buffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl*)*(This->nrofbuffers+1));
1381                 This->buffers[This->nrofbuffers] = *ippdsb;
1382                 This->nrofbuffers++;
1383         }
1384         LeaveCriticalSection(&(This->lock));
1385
1386         IDirectSound_AddRef(iface);
1387
1388         if (dsbd->lpwfxFormat)
1389                 memcpy(&((*ippdsb)->wfx), dsbd->lpwfxFormat, sizeof((*ippdsb)->wfx));
1390
1391         InitializeCriticalSection(&((*ippdsb)->lock));
1392         
1393 #if USE_DSOUND3D
1394         if (dsbd->dwFlags & DSBCAPS_CTRL3D) {
1395                 IDirectSound3DBufferImpl        *ds3db;
1396
1397                 ds3db = (IDirectSound3DBufferImpl*)HeapAlloc(GetProcessHeap(),
1398                         0,sizeof(*ds3db));
1399                 ds3db->ref = 1;
1400                 ds3db->dsb = (*ippdsb);
1401                 ICOM_VTBL(ds3db) = &ds3dbvt;
1402                 (*ippdsb)->ds3db = ds3db;
1403                 ds3db->ds3db.dwSize = sizeof(DS3DBUFFER);
1404                 ds3db->ds3db.vPosition.x.x = 0.0;
1405                 ds3db->ds3db.vPosition.y.y = 0.0;
1406                 ds3db->ds3db.vPosition.z.z = 0.0;
1407                 ds3db->ds3db.vVelocity.x.x = 0.0;
1408                 ds3db->ds3db.vVelocity.y.y = 0.0;
1409                 ds3db->ds3db.vVelocity.z.z = 0.0;
1410                 ds3db->ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1411                 ds3db->ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1412                 ds3db->ds3db.vConeOrientation.x.x = 0.0;
1413                 ds3db->ds3db.vConeOrientation.y.y = 0.0;
1414                 ds3db->ds3db.vConeOrientation.z.z = 0.0;
1415                 ds3db->ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1416                 ds3db->ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
1417                 ds3db->ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1418                 ds3db->ds3db.dwMode = DS3DMODE_NORMAL;
1419                 ds3db->buflen = ((*ippdsb)->buflen * primarybuf->wfx.nBlockAlign) /
1420                         (*ippdsb)->wfx.nBlockAlign;
1421                 ds3db->buffer = HeapAlloc(GetProcessHeap(), 0, ds3db->buflen);
1422                 if (ds3db->buffer == NULL) {
1423                         ds3db->buflen = 0;
1424                         ds3db->ds3db.dwMode = DS3DMODE_DISABLE;
1425                 }
1426         }
1427 #endif
1428         return DS_OK;
1429 }
1430
1431 static HRESULT WINAPI IDirectSoundImpl_DuplicateSoundBuffer(
1432         LPDIRECTSOUND iface,LPDIRECTSOUNDBUFFER pdsb,LPLPDIRECTSOUNDBUFFER ppdsb
1433 ) {
1434         ICOM_THIS(IDirectSoundImpl,iface);
1435         IDirectSoundBufferImpl* ipdsb=(IDirectSoundBufferImpl*)pdsb;
1436         IDirectSoundBufferImpl** ippdsb=(IDirectSoundBufferImpl**)ppdsb;
1437         TRACE("(%p,%p,%p)\n",This,ipdsb,ippdsb);
1438
1439         *ippdsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundBufferImpl));
1440
1441         IDirectSoundBuffer_AddRef(pdsb);
1442         memcpy(*ippdsb, ipdsb, sizeof(IDirectSoundBufferImpl));
1443         (*ippdsb)->ref = 1;
1444         (*ippdsb)->playpos = 0;
1445         (*ippdsb)->writepos = 0;
1446         (*ippdsb)->dsound = This;
1447         (*ippdsb)->parent = ipdsb;
1448         memcpy(&((*ippdsb)->wfx), &(ipdsb->wfx), sizeof((*ippdsb)->wfx));
1449         /* register buffer */
1450         EnterCriticalSection(&(This->lock));
1451         This->buffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl**)*(This->nrofbuffers+1));
1452         This->buffers[This->nrofbuffers] = *ippdsb;
1453         This->nrofbuffers++;
1454         IDirectSound_AddRef(iface);
1455         LeaveCriticalSection(&(This->lock));
1456         return DS_OK;
1457 }
1458
1459
1460 static HRESULT WINAPI IDirectSoundImpl_GetCaps(LPDIRECTSOUND iface,LPDSCAPS caps) {
1461         ICOM_THIS(IDirectSoundImpl,iface);
1462         TRACE("(%p,%p)\n",This,caps);
1463         TRACE("(flags=0x%08lx)\n",caps->dwFlags);
1464
1465         if (caps == NULL)
1466                 return DSERR_INVALIDPARAM;
1467
1468         /* We should check this value, not set it. See Inside DirectX, p215. */
1469         caps->dwSize = sizeof(*caps);
1470
1471         caps->dwFlags =
1472                 DSCAPS_PRIMARYSTEREO |
1473                 DSCAPS_PRIMARY16BIT |
1474                 DSCAPS_SECONDARYSTEREO |
1475                 DSCAPS_SECONDARY16BIT |
1476                 DSCAPS_CONTINUOUSRATE;
1477         /* FIXME: query OSS */
1478         caps->dwMinSecondarySampleRate          = DSBFREQUENCY_MIN;
1479         caps->dwMaxSecondarySampleRate          = DSBFREQUENCY_MAX;
1480
1481         caps->dwPrimaryBuffers                  = 1;
1482
1483         caps->dwMaxHwMixingAllBuffers           = 0;
1484         caps->dwMaxHwMixingStaticBuffers        = 0;
1485         caps->dwMaxHwMixingStreamingBuffers     = 0;
1486
1487         caps->dwFreeHwMixingAllBuffers          = 0;
1488         caps->dwFreeHwMixingStaticBuffers       = 0;
1489         caps->dwFreeHwMixingStreamingBuffers    = 0;
1490
1491         caps->dwMaxHw3DAllBuffers               = 0;
1492         caps->dwMaxHw3DStaticBuffers            = 0;
1493         caps->dwMaxHw3DStreamingBuffers         = 0;
1494
1495         caps->dwFreeHw3DAllBuffers              = 0;
1496         caps->dwFreeHw3DStaticBuffers           = 0;
1497         caps->dwFreeHw3DStreamingBuffers        = 0;
1498
1499         caps->dwTotalHwMemBytes                 = 0;
1500
1501         caps->dwFreeHwMemBytes                  = 0;
1502
1503         caps->dwMaxContigFreeHwMemBytes         = 0;
1504
1505         caps->dwUnlockTransferRateHwBuffers     = 4096; /* But we have none... */
1506
1507         caps->dwPlayCpuOverheadSwBuffers        = 1;    /* 1% */
1508
1509         return DS_OK;
1510 }
1511
1512 static ULONG WINAPI IDirectSoundImpl_AddRef(LPDIRECTSOUND iface) {
1513         ICOM_THIS(IDirectSoundImpl,iface);
1514         return ++(This->ref);
1515 }
1516
1517 static ULONG WINAPI IDirectSoundImpl_Release(LPDIRECTSOUND iface) {
1518         ICOM_THIS(IDirectSoundImpl,iface);
1519         TRACE("(%p), ref was %ld\n",This,This->ref);
1520         if (!--(This->ref)) {
1521                 DSOUND_CloseAudio();
1522                 while(IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)primarybuf)); /* Deallocate */
1523                 FIXME("need to release all buffers!\n");
1524                 HeapFree(GetProcessHeap(),0,This);
1525                 dsound = NULL;
1526                 return S_OK;
1527         }
1528         return This->ref;
1529 }
1530
1531 static HRESULT WINAPI IDirectSoundImpl_SetSpeakerConfig(
1532         LPDIRECTSOUND iface,DWORD config
1533 ) {
1534         ICOM_THIS(IDirectSoundImpl,iface);
1535         FIXME("(%p,0x%08lx):stub\n",This,config);
1536         return DS_OK;
1537 }
1538
1539 static HRESULT WINAPI IDirectSoundImpl_QueryInterface(
1540         LPDIRECTSOUND iface,REFIID riid,LPVOID *ppobj
1541 ) {
1542         ICOM_THIS(IDirectSoundImpl,iface);
1543
1544         if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
1545
1546                 if (This->listener) {
1547                         *ppobj = This->listener;
1548                         return DS_OK;
1549                 }
1550                 This->listener = (IDirectSound3DListenerImpl*)HeapAlloc(
1551                         GetProcessHeap(), 0, sizeof(*(This->listener)));
1552                 This->listener->ref = 1;
1553                 ICOM_VTBL(This->listener) = &ds3dlvt;
1554                 IDirectSound_AddRef(iface);
1555                 This->listener->ds3dl.dwSize = sizeof(DS3DLISTENER);
1556                 This->listener->ds3dl.vPosition.x.x = 0.0;
1557                 This->listener->ds3dl.vPosition.y.y = 0.0;
1558                 This->listener->ds3dl.vPosition.z.z = 0.0;
1559                 This->listener->ds3dl.vVelocity.x.x = 0.0;
1560                 This->listener->ds3dl.vVelocity.y.y = 0.0;
1561                 This->listener->ds3dl.vVelocity.z.z = 0.0;
1562                 This->listener->ds3dl.vOrientFront.x.x = 0.0;
1563                 This->listener->ds3dl.vOrientFront.y.y = 0.0;
1564                 This->listener->ds3dl.vOrientFront.z.z = 1.0;
1565                 This->listener->ds3dl.vOrientTop.x.x = 0.0;
1566                 This->listener->ds3dl.vOrientTop.y.y = 1.0;
1567                 This->listener->ds3dl.vOrientTop.z.z = 0.0;
1568                 This->listener->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
1569                 This->listener->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
1570                 This->listener->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
1571                 *ppobj = (LPVOID)This->listener;
1572                 return DS_OK;
1573         }
1574
1575         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1576         return E_FAIL;
1577 }
1578
1579 static HRESULT WINAPI IDirectSoundImpl_Compact(
1580         LPDIRECTSOUND iface)
1581 {
1582         ICOM_THIS(IDirectSoundImpl,iface);
1583         TRACE("(%p)\n", This);
1584         return DS_OK;
1585 }
1586
1587 static HRESULT WINAPI IDirectSoundImpl_GetSpeakerConfig(
1588         LPDIRECTSOUND iface,
1589         LPDWORD lpdwSpeakerConfig)
1590 {
1591         ICOM_THIS(IDirectSoundImpl,iface);
1592         TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
1593         *lpdwSpeakerConfig = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
1594         return DS_OK;
1595 }
1596
1597 static HRESULT WINAPI IDirectSoundImpl_Initialize(
1598         LPDIRECTSOUND iface,
1599         LPGUID lpGuid)
1600 {
1601         ICOM_THIS(IDirectSoundImpl,iface);
1602         TRACE("(%p, %p)\n", This, lpGuid);
1603         return DS_OK;
1604 }
1605
1606 static ICOM_VTABLE(IDirectSound) dsvt = 
1607 {
1608         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1609         IDirectSoundImpl_QueryInterface,
1610         IDirectSoundImpl_AddRef,
1611         IDirectSoundImpl_Release,
1612         IDirectSoundImpl_CreateSoundBuffer,
1613         IDirectSoundImpl_GetCaps,
1614         IDirectSoundImpl_DuplicateSoundBuffer,
1615         IDirectSoundImpl_SetCooperativeLevel,
1616         IDirectSoundImpl_Compact,
1617         IDirectSoundImpl_GetSpeakerConfig,
1618         IDirectSoundImpl_SetSpeakerConfig,
1619         IDirectSoundImpl_Initialize
1620 };
1621
1622
1623 /* See http://www.opensound.com/pguide/audio.html for more details */
1624
1625 static int
1626 DSOUND_setformat(LPWAVEFORMATEX wfex) {
1627         int     xx,channels,speed,format,nformat;
1628
1629         if (!audioOK) {
1630                 TRACE("(%p) deferred\n", wfex);
1631                 return 0;
1632         }
1633         switch (wfex->wFormatTag) {
1634         default:
1635                 WARN("unknown WAVE_FORMAT tag %d\n",wfex->wFormatTag);
1636                 return DSERR_BADFORMAT;
1637         case WAVE_FORMAT_PCM:
1638                 break;
1639         }
1640         if (wfex->wBitsPerSample==8)
1641                 format = AFMT_U8;
1642         else
1643                 format = AFMT_S16_LE;
1644
1645         if (-1==ioctl(audiofd,SNDCTL_DSP_GETFMTS,&xx)) {
1646                 perror("ioctl SNDCTL_DSP_GETFMTS");
1647                 return -1;
1648         }
1649         if ((xx&format)!=format) {/* format unsupported */
1650                 FIXME("SNDCTL_DSP_GETFMTS: format not supported\n"); 
1651                 return -1;
1652         }
1653         nformat = format;
1654         if (-1==ioctl(audiofd,SNDCTL_DSP_SETFMT,&nformat)) {
1655                 perror("ioctl SNDCTL_DSP_SETFMT");
1656                 return -1;
1657         }
1658         if (nformat!=format) {/* didn't work */
1659                 FIXME("SNDCTL_DSP_GETFMTS: format not set\n"); 
1660                 return -1;
1661         }
1662
1663         channels = wfex->nChannels-1;
1664         if (-1==ioctl(audiofd,SNDCTL_DSP_STEREO,&channels)) {
1665                 perror("ioctl SNDCTL_DSP_STEREO");
1666                 return -1;
1667         }
1668         speed = wfex->nSamplesPerSec;
1669         if (-1==ioctl(audiofd,SNDCTL_DSP_SPEED,&speed)) {
1670                 perror("ioctl SNDCTL_DSP_SPEED");
1671                 return -1;
1672         }
1673         TRACE("(freq=%ld,channels=%d,bits=%d)\n",
1674                 wfex->nSamplesPerSec,wfex->nChannels,wfex->wBitsPerSample
1675         );
1676         return 0;
1677 }
1678
1679 static void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len)
1680 {
1681         int                     i;
1682         DWORD                   offset;
1683         LPDSBPOSITIONNOTIFY     event;
1684
1685         if (dsb->nrofnotifies == 0)
1686                 return;
1687
1688         TRACE("(%p) buflen = %ld, playpos = %ld, len = %d\n",
1689                 dsb, dsb->buflen, dsb->playpos, len);
1690         for (i = 0; i < dsb->nrofnotifies ; i++) {
1691                 event = dsb->notifies + i;
1692                 offset = event->dwOffset;
1693                 TRACE("checking %d, position %ld, event = %d\n",
1694                         i, offset, event->hEventNotify);
1695                 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
1696                 /* OK. [Inside DirectX, p274] */
1697                 /*  */
1698                 /* This also means we can't sort the entries by offset, */
1699                 /* because DSBPN_OFFSETSTOP == -1 */
1700                 if (offset == DSBPN_OFFSETSTOP) {
1701                         if (dsb->playing == 0) {
1702                                 SetEvent(event->hEventNotify);
1703                                 TRACE("signalled event %d (%d)\n", event->hEventNotify, i);
1704                                 return;
1705                         } else
1706                                 return;
1707                 }
1708                 if ((dsb->playpos + len) >= dsb->buflen) {
1709                         if ((offset < ((dsb->playpos + len) % dsb->buflen)) ||
1710                             (offset >= dsb->playpos)) {
1711                                 TRACE("signalled event %d (%d)\n", event->hEventNotify, i);
1712                                 SetEvent(event->hEventNotify);
1713                         }
1714                 } else {
1715                         if ((offset >= dsb->playpos) && (offset < (dsb->playpos + len))) {
1716                                 TRACE("signalled event %d (%d)\n", event->hEventNotify, i);
1717                                 SetEvent(event->hEventNotify);
1718                         }
1719                 }
1720         }
1721 }
1722
1723 /* WAV format info can be found at: */
1724 /* */
1725 /*      http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
1726 /*      ftp://ftp.cwi.nl/pub/audio/RIFF-format */
1727 /* */
1728 /* Import points to remember: */
1729 /* */
1730 /*      8-bit WAV is unsigned */
1731 /*      16-bit WAV is signed */
1732
1733 static inline INT16 cvtU8toS16(BYTE byte)
1734 {
1735         INT16   s = (byte - 128) << 8;
1736
1737         return s;
1738 }
1739
1740 static inline BYTE cvtS16toU8(INT16 word)
1741 {
1742         BYTE    b = (word + 32768) >> 8;
1743         
1744         return b;
1745 }
1746
1747
1748 /* We should be able to optimize these two inline functions */
1749 /* so that we aren't doing 8->16->8 conversions when it is */
1750 /* not necessary. But this is still a WIP. Optimize later. */
1751 static inline void get_fields(const IDirectSoundBufferImpl *dsb, BYTE *buf, INT *fl, INT *fr)
1752 {
1753         INT16   *bufs = (INT16 *) buf;
1754
1755         /* TRACE("(%p)", buf); */
1756         if ((dsb->wfx.wBitsPerSample == 8) && dsb->wfx.nChannels == 2) {
1757                 *fl = cvtU8toS16(*buf);
1758                 *fr = cvtU8toS16(*(buf + 1));
1759                 return;
1760         }
1761
1762         if ((dsb->wfx.wBitsPerSample == 16) && dsb->wfx.nChannels == 2) {
1763                 *fl = *bufs;
1764                 *fr = *(bufs + 1);
1765                 return;
1766         }
1767
1768         if ((dsb->wfx.wBitsPerSample == 8) && dsb->wfx.nChannels == 1) {
1769                 *fl = cvtU8toS16(*buf);
1770                 *fr = *fl;
1771                 return;
1772         }
1773
1774         if ((dsb->wfx.wBitsPerSample == 16) && dsb->wfx.nChannels == 1) {
1775                 *fl = *bufs;
1776                 *fr = *bufs;
1777                 return;
1778         }
1779
1780         FIXME("get_fields found an unsupported configuration\n");
1781         return;
1782 }
1783
1784 static inline void set_fields(BYTE *buf, INT fl, INT fr)
1785 {
1786         INT16 *bufs = (INT16 *) buf;
1787
1788         if ((primarybuf->wfx.wBitsPerSample == 8) && (primarybuf->wfx.nChannels == 2)) {
1789                 *buf = cvtS16toU8(fl);
1790                 *(buf + 1) = cvtS16toU8(fr);
1791                 return;
1792         }
1793
1794         if ((primarybuf->wfx.wBitsPerSample == 16) && (primarybuf->wfx.nChannels == 2)) {
1795                 *bufs = fl;
1796                 *(bufs + 1) = fr;
1797                 return;
1798         }
1799
1800         if ((primarybuf->wfx.wBitsPerSample == 8) && (primarybuf->wfx.nChannels == 1)) {
1801                 *buf = cvtS16toU8((fl + fr) >> 1);
1802                 return;
1803         }
1804
1805         if ((primarybuf->wfx.wBitsPerSample == 16) && (primarybuf->wfx.nChannels == 1)) {
1806                 *bufs = (fl + fr) >> 1;
1807                 return;
1808         }
1809         FIXME("set_fields found an unsupported configuration\n");
1810         return;
1811 }
1812
1813 /* Now with PerfectPitch (tm) technology */
1814 static INT DSOUND_MixerNorm(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
1815 {
1816         INT     i, size, ipos, ilen, fieldL, fieldR;
1817         BYTE    *ibp, *obp;
1818         INT     iAdvance = dsb->wfx.nBlockAlign;
1819         INT     oAdvance = primarybuf->wfx.nBlockAlign;
1820
1821         ibp = dsb->buffer + dsb->playpos;
1822         obp = buf;
1823
1824         TRACE("(%p, %p, %p), playpos=%8.8lx\n", dsb, ibp, obp, dsb->playpos);
1825         /* Check for the best case */
1826         if ((dsb->freq == primarybuf->wfx.nSamplesPerSec) &&
1827             (dsb->wfx.wBitsPerSample == primarybuf->wfx.wBitsPerSample) &&
1828             (dsb->wfx.nChannels == primarybuf->wfx.nChannels)) {
1829                 DWORD bytesleft = dsb->buflen - dsb->playpos;
1830                 TRACE("(%p) Best case\n", dsb);
1831                 if (len <= bytesleft )
1832                         memcpy(obp, ibp, len);
1833                 else { /* wrap */
1834                         memcpy(obp, ibp, bytesleft );
1835                         memcpy(obp + bytesleft, dsb->buffer, len - bytesleft);
1836                 }
1837                 return len;
1838         }
1839         
1840         /* Check for same sample rate */
1841         if (dsb->freq == primarybuf->wfx.nSamplesPerSec) {
1842                 TRACE("(%p) Same sample rate %ld = primary %ld\n", dsb,
1843                         dsb->freq, primarybuf->wfx.nSamplesPerSec);
1844                 ilen = 0;
1845                 for (i = 0; i < len; i += oAdvance) {
1846                         get_fields(dsb, ibp, &fieldL, &fieldR);
1847                         ibp += iAdvance;
1848                         ilen += iAdvance;
1849                         set_fields(obp, fieldL, fieldR);
1850                         obp += oAdvance;
1851                         if (ibp >= (BYTE *)(dsb->buffer + dsb->buflen))
1852                                 ibp = dsb->buffer;      /* wrap */
1853                 }
1854                 return (ilen);  
1855         }
1856
1857         /* Mix in different sample rates */
1858         /* */
1859         /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
1860         /* Patent Pending :-] */
1861
1862         TRACE("(%p) Adjusting frequency: %ld -> %ld\n",
1863                 dsb, dsb->freq, primarybuf->wfx.nSamplesPerSec);
1864
1865         size = len / oAdvance;
1866         ilen = ((size * dsb->freqAdjust) >> DSOUND_FREQSHIFT) * iAdvance;
1867         for (i = 0; i < size; i++) {
1868
1869                 ipos = (((i * dsb->freqAdjust) >> DSOUND_FREQSHIFT) * iAdvance) + dsb->playpos;
1870
1871                 if (ipos >= dsb->buflen)
1872                         ipos %= dsb->buflen;    /* wrap */
1873
1874                 get_fields(dsb, (dsb->buffer + ipos), &fieldL, &fieldR);
1875                 set_fields(obp, fieldL, fieldR);
1876                 obp += oAdvance;
1877         }
1878         return ilen;
1879 }
1880
1881 static void DSOUND_MixerVol(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
1882 {
1883         INT     i, inc = primarybuf->wfx.wBitsPerSample >> 3;
1884         BYTE    *bpc = buf;
1885         INT16   *bps = (INT16 *) buf;
1886         
1887         TRACE("(%p) left = %lx, right = %lx\n", dsb,
1888                 dsb->lVolAdjust, dsb->rVolAdjust);
1889         if ((!(dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || (dsb->pan == 0)) &&
1890             (!(dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) || (dsb->volume == 0)) &&
1891             !(dsb->dsbd.dwFlags & DSBCAPS_CTRL3D))
1892                 return;         /* Nothing to do */
1893
1894         /* If we end up with some bozo coder using panning or 3D sound */
1895         /* with a mono primary buffer, it could sound very weird using */
1896         /* this method. Oh well, tough patooties. */
1897
1898         for (i = 0; i < len; i += inc) {
1899                 INT     val;
1900
1901                 switch (inc) {
1902
1903                 case 1:
1904                         /* 8-bit WAV is unsigned, but we need to operate */
1905                         /* on signed data for this to work properly */
1906                         val = *bpc - 128;
1907                         val = ((val * (i & inc ? dsb->rVolAdjust : dsb->lVolAdjust)) >> 15);
1908                         *bpc = val + 128;
1909                         bpc++;
1910                         break;
1911                 case 2:
1912                         /* 16-bit WAV is signed -- much better */
1913                         val = *bps;
1914                         val = ((val * ((i & inc) ? dsb->rVolAdjust : dsb->lVolAdjust)) >> 15);
1915                         *bps = val;
1916                         bps++;
1917                         break;
1918                 default:
1919                         /* Very ugly! */
1920                         FIXME("MixerVol had a nasty error\n");
1921                 }
1922         }               
1923 }
1924
1925 #ifdef USE_DSOUND3D
1926 static void DSOUND_Mixer3D(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
1927 {
1928         BYTE    *ibp, *obp;
1929         DWORD   buflen, playpos;
1930
1931         buflen = dsb->ds3db->buflen;
1932         playpos = (dsb->playpos * primarybuf->wfx.nBlockAlign) / dsb->wfx.nBlockAlign;
1933         ibp = dsb->ds3db->buffer + playpos;
1934         obp = buf;
1935
1936         if (playpos > buflen) {
1937                 FIXME("Major breakage");
1938                 return;
1939         }
1940
1941         if (len <= (playpos + buflen))
1942                 memcpy(obp, ibp, len);
1943         else { /* wrap */
1944                 memcpy(obp, ibp, buflen - playpos);
1945                 memcpy(obp + (buflen - playpos),
1946                     dsb->buffer,
1947                     len - (buflen - playpos));
1948         }
1949         return;
1950 }
1951 #endif
1952
1953 static void *tmp_buffer;
1954 static size_t tmp_buffer_len = 0;
1955
1956 static void *DSOUND_tmpbuffer(size_t len)
1957 {
1958   if (len>tmp_buffer_len) {
1959     void *new_buffer = realloc(tmp_buffer, len);
1960     if (new_buffer) {
1961       tmp_buffer = new_buffer;
1962       tmp_buffer_len = len;
1963     }
1964     return new_buffer;
1965   }
1966   return tmp_buffer;
1967 }
1968
1969 static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb)
1970 {
1971         INT     i, len, ilen, temp, field;
1972         INT     advance = primarybuf->wfx.wBitsPerSample >> 3;
1973         BYTE    *buf, *ibuf, *obuf;
1974         INT16   *ibufs, *obufs;
1975
1976         len = DSOUND_FRAGLEN;                   /* The most we will use */
1977         if (!(dsb->playflags & DSBPLAY_LOOPING)) {
1978                 temp = MulDiv(primarybuf->wfx.nAvgBytesPerSec, dsb->buflen,
1979                         dsb->nAvgBytesPerSec) -
1980                        MulDiv(primarybuf->wfx.nAvgBytesPerSec, dsb->playpos,
1981                         dsb->nAvgBytesPerSec);
1982                 len = (len > temp) ? temp : len;
1983         }
1984         len &= ~3;                              /* 4 byte alignment */
1985
1986         if (len == 0) {
1987                 /* This should only happen if we aren't looping and temp < 4 */
1988
1989                 /* We skip the remainder, so check for possible events */
1990                 DSOUND_CheckEvent(dsb, dsb->buflen - dsb->playpos);
1991                 /* Stop */
1992                 dsb->playing = 0;
1993                 dsb->writepos = 0;
1994                 dsb->playpos = 0;
1995                 /* Check for DSBPN_OFFSETSTOP */
1996                 DSOUND_CheckEvent(dsb, 0);
1997                 return 0;
1998         }
1999
2000         /* Been seeing segfaults in malloc() for some reason... */
2001         TRACE("allocating buffer (size = %d)\n", len);
2002         if ((buf = ibuf = (BYTE *) DSOUND_tmpbuffer(len)) == NULL)
2003                 return 0;
2004
2005         TRACE("MixInBuffer (%p) len = %d\n", dsb, len);
2006
2007         ilen = DSOUND_MixerNorm(dsb, ibuf, len);
2008         if ((dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
2009             (dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME))
2010                 DSOUND_MixerVol(dsb, ibuf, len);
2011
2012         obuf = primarybuf->buffer + primarybuf->playpos;
2013         for (i = 0; i < len; i += advance) {
2014                 obufs = (INT16 *) obuf;
2015                 ibufs = (INT16 *) ibuf;
2016                 if (primarybuf->wfx.wBitsPerSample == 8) {
2017                         /* 8-bit WAV is unsigned */
2018                         field = (*ibuf - 128);
2019                         field += (*obuf - 128);
2020                         field = field > 127 ? 127 : field;
2021                         field = field < -128 ? -128 : field;
2022                         *obuf = field + 128;
2023                 } else {
2024                         /* 16-bit WAV is signed */
2025                         field = *ibufs;
2026                         field += *obufs;
2027                         field = field > 32767 ? 32767 : field;
2028                         field = field < -32768 ? -32768 : field;
2029                         *obufs = field;
2030                 }
2031                 ibuf += advance;
2032                 obuf += advance;
2033                 if (obuf >= (BYTE *)(primarybuf->buffer + primarybuf->buflen))
2034                         obuf = primarybuf->buffer;
2035         }
2036         /* free(buf); */
2037
2038         if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY)
2039                 DSOUND_CheckEvent(dsb, ilen);
2040
2041         dsb->playpos += ilen;
2042         dsb->writepos = dsb->playpos + ilen;
2043         
2044         if (dsb->playpos >= dsb->buflen) {
2045                 if (!(dsb->playflags & DSBPLAY_LOOPING)) {
2046                         dsb->playing = 0;
2047                         dsb->writepos = 0;
2048                         dsb->playpos = 0;
2049                         DSOUND_CheckEvent(dsb, 0);              /* For DSBPN_OFFSETSTOP */
2050                 } else
2051                         dsb->playpos %= dsb->buflen;            /* wrap */
2052         }
2053         
2054         if (dsb->writepos >= dsb->buflen)
2055                 dsb->writepos %= dsb->buflen;
2056
2057         return len;
2058 }
2059
2060 static DWORD WINAPI DSOUND_MixPrimary(void)
2061 {
2062         INT                     i, len, maxlen = 0;
2063         IDirectSoundBufferImpl  *dsb;
2064
2065         for (i = dsound->nrofbuffers - 1; i >= 0; i--) {
2066                 dsb = dsound->buffers[i];
2067
2068                 if (!dsb || !(ICOM_VTBL(dsb)))
2069                         continue;
2070                 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);
2071                 if (dsb->buflen && dsb->playing) {
2072                         EnterCriticalSection(&(dsb->lock));
2073                         len = DSOUND_MixInBuffer(dsb);
2074                         maxlen = len > maxlen ? len : maxlen;
2075                         LeaveCriticalSection(&(dsb->lock));
2076                 }
2077                 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)dsb);
2078         }
2079         
2080         return maxlen;
2081 }
2082
2083 static int DSOUND_OpenAudio(void)
2084 {
2085         int     audioFragment,flags;
2086
2087         if (primarybuf == NULL)
2088                 return DSERR_OUTOFMEMORY;
2089
2090         while (audiofd >= 0)
2091
2092                 sleep(5);
2093         /* we will most likely not get one, avoid excessive opens ... */
2094         if (audiofd == -ENODEV)
2095                 return -1;
2096         audiofd = open("/dev/audio",O_WRONLY|O_NDELAY);
2097         if (audiofd==-1) {
2098                 /* Don't worry if sound is busy at the moment */
2099                 if ((errno != EBUSY) && (errno != ENODEV))
2100                         perror("open /dev/audio");
2101                 audiofd = -errno;
2102                 return -1; /* -1 */
2103         }
2104
2105         /* We should probably do something here if SETFRAGMENT fails... */
2106         audioFragment=0x0002000c;
2107         if (-1==ioctl(audiofd,SNDCTL_DSP_SETFRAGMENT,&audioFragment))
2108                 perror("ioctl SETFRAGMENT");
2109         
2110         if ((flags = fcntl(audiofd,F_GETFL,0)) != -1) {
2111             flags &= ~O_NDELAY;
2112             if (-1==fcntl(audiofd,F_SETFL,flags))
2113                 perror("clearing the non-blocking flags in DSOUND_OpenAudio");
2114         } else 
2115             perror("cannot get flags of audiofd");
2116
2117         audioOK = 1;
2118         DSOUND_setformat(&(primarybuf->wfx));
2119
2120         return 0;
2121 }
2122
2123 static void DSOUND_CloseAudio(void)
2124 {
2125         int     neutral;
2126         
2127         neutral = primarybuf->wfx.wBitsPerSample == 8 ? 128 : 0;
2128         audioOK = 0;    /* race condition */
2129         Sleep(5);
2130         /* It's possible we've been called with audio closed */
2131         /* from SetFormat()... this is just to force a call */
2132         /* to OpenAudio() to reset the hardware properly */
2133         if (audiofd >= 0)
2134                 close(audiofd);
2135         primarybuf->playpos = 0;
2136         primarybuf->writepos = DSOUND_FRAGLEN;
2137         memset(primarybuf->buffer, neutral, primarybuf->buflen);
2138         audiofd = -1;
2139         TRACE("Audio stopped\n");
2140 }
2141         
2142 static int DSOUND_WriteAudio(char *buf, int len)
2143 {
2144         int     result, left = 0;
2145
2146         while (left < len) {
2147                 result = write(audiofd, buf + left, len - left);
2148                 if (result == -1) {
2149                         if (errno == EINTR)
2150                                 continue;
2151                         else
2152                                 return result;
2153                 }
2154                 left += result;
2155         }
2156         return 0;
2157 }
2158
2159 static void DSOUND_OutputPrimary(int len)
2160 {
2161         int     neutral, flen1, flen2;
2162         char    *frag1, *frag2;
2163         
2164         /* This is a bad place for this. We need to clear the */
2165         /* buffer with a neutral value, for unsigned 8-bit WAVE */
2166         /* that's 128, for signed 16-bit it's 0 */
2167         neutral = primarybuf->wfx.wBitsPerSample == 8 ? 128 : 0;
2168         
2169         /* **** */
2170         EnterCriticalSection(&(primarybuf->lock));
2171
2172         /* Write out the  */
2173         if ((audioOK == 1) || (DSOUND_OpenAudio() == 0)) {
2174                 if (primarybuf->playpos + len >= primarybuf->buflen) {
2175                         frag1 = primarybuf->buffer + primarybuf->playpos;
2176                         flen1 = primarybuf->buflen - primarybuf->playpos;
2177                         frag2 = primarybuf->buffer;
2178                         flen2 = len - (primarybuf->buflen - primarybuf->playpos);
2179                         if (DSOUND_WriteAudio(frag1, flen1) != 0) {
2180                                 perror("DSOUND_WriteAudio");
2181                                 LeaveCriticalSection(&(primarybuf->lock));
2182                                 ExitThread(0);
2183                         }
2184                         memset(frag1, neutral, flen1);
2185                         if (DSOUND_WriteAudio(frag2, flen2) != 0) {
2186                                 perror("DSOUND_WriteAudio");
2187                                 LeaveCriticalSection(&(primarybuf->lock));
2188                                 ExitThread(0);
2189                         }
2190                         memset(frag2, neutral, flen2);
2191                 } else {
2192                         frag1 = primarybuf->buffer + primarybuf->playpos;
2193                         flen1 = len;
2194                         if (DSOUND_WriteAudio(frag1, flen1) != 0) {
2195                                 perror("DSOUND_WriteAudio");
2196                                 LeaveCriticalSection(&(primarybuf->lock));
2197                                 ExitThread(0);
2198                         }
2199                         memset(frag1, neutral, flen1);
2200                 }
2201         } else {
2202                 /* Can't play audio at the moment -- we need to sleep */
2203                 /* to make up for the time we'd be blocked in write() */
2204                 /* to /dev/audio */
2205                 Sleep(60);
2206         }
2207         primarybuf->playpos += len;
2208         if (primarybuf->playpos >= primarybuf->buflen)
2209                 primarybuf->playpos %= primarybuf->buflen;
2210         primarybuf->writepos = primarybuf->playpos + DSOUND_FRAGLEN;
2211         if (primarybuf->writepos >= primarybuf->buflen)
2212                 primarybuf->writepos %= primarybuf->buflen;
2213
2214         LeaveCriticalSection(&(primarybuf->lock));
2215         /* **** */
2216 }
2217
2218 static DWORD WINAPI DSOUND_thread(LPVOID arg)
2219 {
2220         int     len;
2221
2222         TRACE("dsound is at pid %d\n",getpid());
2223         while (1) {
2224                 if (!dsound) {
2225                         WARN("DSOUND thread giving up.\n");
2226                         ExitThread(0);
2227                 }
2228 #if 0
2229                 /* EP: since the thread creating this thread can
2230                  * die before the end of the DSOUND one, this
2231                  * test is of no use
2232                  * What shall be tested is whether the DSOUND thread 
2233                  * is the last one in the process
2234                  */
2235                 if (getppid()==1) {
2236                         WARN("DSOUND father died? Giving up.\n");
2237                         ExitThread(0);
2238                 }
2239 #endif
2240                 /* RACE: dsound could be deleted */
2241                 EnterCriticalSection(&(dsound->lock));
2242                 if (primarybuf == NULL) {
2243                         /* Should never happen */
2244                         WARN("Lost the primary buffer!\n");
2245                         IDirectSound_Release((LPDIRECTSOUND)dsound);
2246                         ExitThread(0);
2247                 }
2248
2249                 EnterCriticalSection(&(primarybuf->lock));
2250
2251                 len = DSOUND_MixPrimary();
2252
2253                 LeaveCriticalSection(&(primarybuf->lock));
2254                 LeaveCriticalSection(&(dsound->lock));
2255
2256                 if (primarybuf->playing)
2257                         len = DSOUND_FRAGLEN > len ? DSOUND_FRAGLEN : len;
2258                 if (len) {
2259                         /* This does all the work */
2260                         DSOUND_OutputPrimary(len);
2261                 } else {
2262                         /* no buffers playing -- close and wait */
2263                         if (audioOK)
2264                                 DSOUND_CloseAudio();
2265                         Sleep(100);
2266                 }
2267         }
2268         ExitThread(0);
2269 }
2270
2271 #endif /* HAVE_OSS */
2272
2273 /*******************************************************************************
2274  *              DirectSoundCreate
2275  */
2276 HRESULT WINAPI DirectSoundCreate(REFGUID lpGUID,LPDIRECTSOUND *ppDS,IUnknown *pUnkOuter )
2277 {
2278         IDirectSoundImpl** ippDS=(IDirectSoundImpl**)ppDS;
2279         if (lpGUID)
2280                 TRACE("(%p,%p,%p)\n",lpGUID,ippDS,pUnkOuter);
2281         else
2282                 TRACE("DirectSoundCreate (%p)\n", ippDS);
2283
2284 #ifdef HAVE_OSS
2285
2286         if (ippDS == NULL)
2287                 return DSERR_INVALIDPARAM;
2288
2289         if (primarybuf) {
2290                 IDirectSound_AddRef((LPDIRECTSOUND)dsound);
2291                 *ippDS = dsound;
2292                 return DS_OK;
2293         }
2294
2295         /* Check that we actually have audio capabilities */
2296         /* If we do, whether it's busy or not, we continue */
2297         /* otherwise we return with DSERR_NODRIVER */
2298
2299         audiofd = open("/dev/audio",O_WRONLY|O_NDELAY);
2300         if (audiofd == -1) {
2301                 audiofd = -errno;
2302                 if (errno == ENODEV) {
2303                         MESSAGE("No sound hardware found, but continuing anyway.\n");
2304                 } else if (errno == EBUSY) {
2305                         MESSAGE("Sound device busy, will keep trying.\n");
2306                 } else {
2307                         MESSAGE("Unexpected error (%d) while checking for sound support.\n",errno);
2308                         return DSERR_GENERIC;
2309                 }
2310         } else {
2311                 close(audiofd);
2312                 audiofd = -1;
2313         }
2314
2315         *ippDS = (IDirectSoundImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundImpl));
2316         if (*ippDS == NULL)
2317                 return DSERR_OUTOFMEMORY;
2318
2319         (*ippDS)->ref           = 1;
2320         ICOM_VTBL(*ippDS)       = &dsvt;
2321         (*ippDS)->buffers       = NULL;
2322         (*ippDS)->nrofbuffers   = 0;
2323
2324         (*ippDS)->wfx.wFormatTag                = 1;
2325         (*ippDS)->wfx.nChannels         = 2;
2326         (*ippDS)->wfx.nSamplesPerSec    = 22050;
2327         (*ippDS)->wfx.nAvgBytesPerSec   = 44100;
2328         (*ippDS)->wfx.nBlockAlign       = 2;
2329         (*ippDS)->wfx.wBitsPerSample    = 8;
2330
2331         InitializeCriticalSection(&((*ippDS)->lock));
2332
2333         if (!dsound) {
2334                 HANDLE  hnd;
2335                 DWORD           xid;
2336
2337                 dsound = (*ippDS);
2338                 if (primarybuf == NULL) {
2339                         DSBUFFERDESC    dsbd;
2340                         HRESULT         hr;
2341
2342                         dsbd.dwSize = sizeof(DSBUFFERDESC);
2343                         dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
2344                         dsbd.dwBufferBytes = 0;
2345                         dsbd.lpwfxFormat = &(dsound->wfx);
2346                         hr = IDirectSound_CreateSoundBuffer(*ppDS, &dsbd, (LPDIRECTSOUNDBUFFER*)&primarybuf, NULL);
2347                         if (hr != DS_OK)
2348                                 return hr;
2349                         dsound->primary = primarybuf;
2350                 }
2351                 memset(primarybuf->buffer, 128, primarybuf->buflen);
2352                 hnd = CreateThread(NULL,0,DSOUND_thread,0,0,&xid);
2353         }
2354         return DS_OK;
2355 #else
2356         MessageBoxA(0,"DirectSound needs the Open Sound System Driver, which has not been found by ./configure.","WINE DirectSound",MB_OK|MB_ICONSTOP);
2357         return DSERR_NODRIVER;
2358 #endif
2359 }
2360
2361 /*******************************************************************************
2362  * DirectSound ClassFactory
2363  */
2364 typedef struct
2365 {
2366     /* IUnknown fields */
2367     ICOM_VFIELD(IClassFactory);
2368     DWORD                       ref;
2369 } IClassFactoryImpl;
2370
2371 static HRESULT WINAPI 
2372 DSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2373         ICOM_THIS(IClassFactoryImpl,iface);
2374
2375         FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2376         return E_NOINTERFACE;
2377 }
2378
2379 static ULONG WINAPI
2380 DSCF_AddRef(LPCLASSFACTORY iface) {
2381         ICOM_THIS(IClassFactoryImpl,iface);
2382         return ++(This->ref);
2383 }
2384
2385 static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface) {
2386         ICOM_THIS(IClassFactoryImpl,iface);
2387         /* static class, won't be  freed */
2388         return --(This->ref);
2389 }
2390
2391 static HRESULT WINAPI DSCF_CreateInstance(
2392         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2393 ) {
2394         ICOM_THIS(IClassFactoryImpl,iface);
2395
2396         TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
2397         if ( IsEqualGUID( &IID_IDirectSound, riid ) ) {
2398                 /* FIXME: reuse already created dsound if present? */
2399                 return DirectSoundCreate(riid,(LPDIRECTSOUND*)ppobj,pOuter);
2400         }
2401         return E_NOINTERFACE;
2402 }
2403
2404 static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2405         ICOM_THIS(IClassFactoryImpl,iface);
2406         FIXME("(%p)->(%d),stub!\n",This,dolock);
2407         return S_OK;
2408 }
2409
2410 static ICOM_VTABLE(IClassFactory) DSCF_Vtbl = {
2411         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2412         DSCF_QueryInterface,
2413         DSCF_AddRef,
2414         DSCF_Release,
2415         DSCF_CreateInstance,
2416         DSCF_LockServer
2417 };
2418 static IClassFactoryImpl DSOUND_CF = {&DSCF_Vtbl, 1 };
2419
2420 /*******************************************************************************
2421  * DllGetClassObject [DSOUND.4]
2422  * Retrieves class object from a DLL object
2423  *
2424  * NOTES
2425  *    Docs say returns STDAPI
2426  *
2427  * PARAMS
2428  *    rclsid [I] CLSID for the class object
2429  *    riid   [I] Reference to identifier of interface for class object
2430  *    ppv    [O] Address of variable to receive interface pointer for riid
2431  *
2432  * RETURNS
2433  *    Success: S_OK
2434  *    Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
2435  *             E_UNEXPECTED
2436  */
2437 DWORD WINAPI DSOUND_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv)
2438 {
2439     TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
2440     if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
2441         *ppv = (LPVOID)&DSOUND_CF;
2442         IClassFactory_AddRef((IClassFactory*)*ppv);
2443     return S_OK;
2444     }
2445
2446     FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
2447     return CLASS_E_CLASSNOTAVAILABLE;
2448 }
2449
2450
2451 /*******************************************************************************
2452  * DllCanUnloadNow [DSOUND.3]  Determines whether the DLL is in use.
2453  *
2454  * RETURNS
2455  *    Success: S_OK
2456  *    Failure: S_FALSE
2457  */
2458 DWORD WINAPI DSOUND_DllCanUnloadNow(void)
2459 {
2460     FIXME("(void): stub\n");
2461     return S_FALSE;
2462 }