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