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