comctl32: A couple fixes for tab icon offsets.
[wine] / dlls / dsound / tests / ds3d.c
1 /*
2  * Tests the panning and 3D functions of DirectSound
3  *
4  * Part of this test involves playing test tones. But this only makes
5  * sense if someone is going to carefully listen to it, and would only
6  * bother everyone else.
7  * So this is only done if the test is being run in interactive mode.
8  *
9  * Copyright (c) 2002-2004 Francois Gouget
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */
25
26 #define NONAMELESSSTRUCT
27 #define NONAMELESSUNION
28 #include <windows.h>
29
30 #include <math.h>
31
32 #include "wine/test.h"
33 #include "dsound.h"
34 #include "dxerr8.h"
35
36 #include "dsound_test.h"
37
38 #define PI 3.14159265358979323846
39 char* wave_generate_la(WAVEFORMATEX* wfx, double duration, DWORD* size)
40 {
41     int i;
42     int nb_samples;
43     char* buf;
44     char* b;
45
46     nb_samples=(int)(duration*wfx->nSamplesPerSec);
47     *size=nb_samples*wfx->nBlockAlign;
48     b=buf=malloc(*size);
49     for (i=0;i<nb_samples;i++) {
50         double y=sin(440.0*2*PI*i/wfx->nSamplesPerSec);
51         if (wfx->wBitsPerSample==8) {
52             unsigned char sample=(unsigned char)((double)127.5*(y+1.0));
53             *b++=sample;
54             if (wfx->nChannels==2)
55                 *b++=sample;
56         } else {
57             signed short sample=(signed short)((double)32767.5*y-0.5);
58             b[0]=sample & 0xff;
59             b[1]=sample >> 8;
60             b+=2;
61             if (wfx->nChannels==2) {
62                 b[0]=sample & 0xff;
63                 b[1]=sample >> 8;
64                 b+=2;
65             }
66         }
67     }
68     return buf;
69 }
70
71 const char * getDSBCAPS(DWORD xmask) {
72     static struct {
73         DWORD   mask;
74         const char    *name;
75     } flags[] = {
76 #define FE(x) { x, #x },
77         FE(DSBCAPS_PRIMARYBUFFER)
78         FE(DSBCAPS_STATIC)
79         FE(DSBCAPS_LOCHARDWARE)
80         FE(DSBCAPS_LOCSOFTWARE)
81         FE(DSBCAPS_CTRL3D)
82         FE(DSBCAPS_CTRLFREQUENCY)
83         FE(DSBCAPS_CTRLPAN)
84         FE(DSBCAPS_CTRLVOLUME)
85         FE(DSBCAPS_CTRLPOSITIONNOTIFY)
86         FE(DSBCAPS_STICKYFOCUS)
87         FE(DSBCAPS_GLOBALFOCUS)
88         FE(DSBCAPS_GETCURRENTPOSITION2)
89         FE(DSBCAPS_MUTE3DATMAXDISTANCE)
90 #undef FE
91     };
92     static char buffer[512];
93     unsigned int i;
94     BOOL first = TRUE;
95
96     buffer[0] = 0;
97
98     for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++) {
99         if ((flags[i].mask & xmask) == flags[i].mask) {
100             if (first)
101                 first = FALSE;
102             else
103                 strcat(buffer, "|");
104             strcat(buffer, flags[i].name);
105         }
106     }
107
108     return buffer;
109 }
110
111 HWND get_hwnd()
112 {
113     HWND hwnd=GetForegroundWindow();
114     if (!hwnd)
115         hwnd=GetDesktopWindow();
116     return hwnd;
117 }
118
119 void init_format(WAVEFORMATEX* wfx, int format, int rate, int depth,
120                  int channels)
121 {
122     wfx->wFormatTag=format;
123     wfx->nChannels=channels;
124     wfx->wBitsPerSample=depth;
125     wfx->nSamplesPerSec=rate;
126     wfx->nBlockAlign=wfx->nChannels*wfx->wBitsPerSample/8;
127     /* FIXME: Shouldn't this test be if (format!=WAVE_FORMAT_PCM) */
128     if (wfx->nBlockAlign==0)
129     {
130         /* align compressed formats to byte boundary */
131         wfx->nBlockAlign=1;
132     }
133     wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nBlockAlign;
134     wfx->cbSize=0;
135 }
136
137 typedef struct {
138     char* wave;
139     DWORD wave_len;
140
141     LPDIRECTSOUNDBUFFER dsbo;
142     LPWAVEFORMATEX wfx;
143     DWORD buffer_size;
144     DWORD written;
145     DWORD played;
146     DWORD offset;
147 } play_state_t;
148
149 static int buffer_refill(play_state_t* state, DWORD size)
150 {
151     LPVOID ptr1,ptr2;
152     DWORD len1,len2;
153     HRESULT rc;
154
155     if (size>state->wave_len-state->written)
156         size=state->wave_len-state->written;
157
158     rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
159                                &ptr1,&len1,&ptr2,&len2,0);
160     ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %s\n",
161        DXGetErrorString8(rc));
162     if (rc!=DS_OK)
163         return -1;
164
165     memcpy(ptr1,state->wave+state->written,len1);
166     state->written+=len1;
167     if (ptr2!=NULL) {
168         memcpy(ptr2,state->wave+state->written,len2);
169         state->written+=len2;
170     }
171     state->offset=state->written % state->buffer_size;
172     rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2);
173     ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %s\n",
174        DXGetErrorString8(rc));
175     if (rc!=DS_OK)
176         return -1;
177     return size;
178 }
179
180 static int buffer_silence(play_state_t* state, DWORD size)
181 {
182     LPVOID ptr1,ptr2;
183     DWORD len1,len2;
184     HRESULT rc;
185     BYTE s;
186
187     rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
188                                &ptr1,&len1,&ptr2,&len2,0);
189     ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %s\n",
190        DXGetErrorString8(rc));
191     if (rc!=DS_OK)
192         return -1;
193
194     s=(state->wfx->wBitsPerSample==8?0x80:0);
195     memset(ptr1,s,len1);
196     if (ptr2!=NULL) {
197         memset(ptr2,s,len2);
198     }
199     state->offset=(state->offset+size) % state->buffer_size;
200     rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2);
201     ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %s\n",
202        DXGetErrorString8(rc));
203     if (rc!=DS_OK)
204         return -1;
205     return size;
206 }
207
208 static int buffer_service(play_state_t* state)
209 {
210     DWORD last_play_pos,play_pos,buf_free;
211     HRESULT rc;
212
213     rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,NULL);
214     ok(rc==DS_OK,"IDirectSoundBuffer_GetCurrentPosition() failed: %s\n",
215        DXGetErrorString8(rc));
216     if (rc!=DS_OK) {
217         goto STOP;
218     }
219
220     /* Update the amount played */
221     last_play_pos=state->played % state->buffer_size;
222     if (play_pos<last_play_pos)
223         state->played+=state->buffer_size-last_play_pos+play_pos;
224     else
225         state->played+=play_pos-last_play_pos;
226
227     if (winetest_debug > 1)
228         trace("buf size=%ld last_play_pos=%ld play_pos=%ld played=%ld / %ld\n",
229               state->buffer_size,last_play_pos,play_pos,state->played,
230               state->wave_len);
231
232     if (state->played>state->wave_len)
233     {
234         /* Everything has been played */
235         goto STOP;
236     }
237
238     /* Refill the buffer */
239     if (state->offset<=play_pos)
240         buf_free=play_pos-state->offset;
241     else
242         buf_free=state->buffer_size-state->offset+play_pos;
243
244     if (winetest_debug > 1)
245         trace("offset=%ld free=%ld written=%ld / %ld\n",
246               state->offset,buf_free,state->written,state->wave_len);
247     if (buf_free==0)
248         return 1;
249
250     if (state->written<state->wave_len)
251     {
252         int w=buffer_refill(state,buf_free);
253         if (w==-1)
254             goto STOP;
255         buf_free-=w;
256         if (state->written==state->wave_len && winetest_debug > 1)
257             trace("last sound byte at %ld\n",
258                   (state->written % state->buffer_size));
259     }
260
261     if (buf_free>0) {
262         /* Fill with silence */
263         if (winetest_debug > 1)
264             trace("writing %ld bytes of silence\n",buf_free);
265         if (buffer_silence(state,buf_free)==-1)
266             goto STOP;
267     }
268     return 1;
269
270 STOP:
271     if (winetest_debug > 1)
272         trace("stopping playback\n");
273     rc=IDirectSoundBuffer_Stop(state->dsbo);
274     ok(rc==DS_OK,"IDirectSoundBuffer_Stop() failed: %s\n",
275        DXGetErrorString8(rc));
276     return 0;
277 }
278
279 void test_buffer(LPDIRECTSOUND dso, LPDIRECTSOUNDBUFFER *dsbo,
280                  BOOL is_primary, BOOL set_volume, LONG volume,
281                  BOOL set_pan, LONG pan, BOOL play, double duration,
282                  BOOL buffer3d, LPDIRECTSOUND3DLISTENER listener,
283                  BOOL move_listener, BOOL move_sound,
284                  BOOL set_frequency, DWORD frequency)
285 {
286     HRESULT rc;
287     DSBCAPS dsbcaps;
288     WAVEFORMATEX wfx,wfx2;
289     DWORD size,status,freq;
290     int ref;
291
292     if (set_frequency) {
293         rc=IDirectSoundBuffer_SetFrequency(*dsbo,frequency);
294         ok(rc==DS_OK||rc==DSERR_CONTROLUNAVAIL,
295            "IDirectSoundBuffer_SetFrequency() failed to set frequency "
296            "%s\n",DXGetErrorString8(rc));
297         if (rc!=DS_OK)
298             return;
299     }
300
301     /* DSOUND: Error: Invalid caps pointer */
302     rc=IDirectSoundBuffer_GetCaps(*dsbo,0);
303     ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have "
304        "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc));
305
306     ZeroMemory(&dsbcaps, sizeof(dsbcaps));
307
308     /* DSOUND: Error: Invalid caps pointer */
309     rc=IDirectSoundBuffer_GetCaps(*dsbo,&dsbcaps);
310     ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have "
311        "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc));
312
313     dsbcaps.dwSize=sizeof(dsbcaps);
314     rc=IDirectSoundBuffer_GetCaps(*dsbo,&dsbcaps);
315     ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %s\n",
316        DXGetErrorString8(rc));
317     if (rc==DS_OK && winetest_debug > 1) {
318         trace("    Caps: flags=0x%08lx size=%ld\n",dsbcaps.dwFlags,
319               dsbcaps.dwBufferBytes);
320     }
321
322     /* Query the format size. Note that it may not match sizeof(wfx) */
323     size=0;
324     rc=IDirectSoundBuffer_GetFormat(*dsbo,NULL,0,&size);
325     ok(rc==DS_OK && size!=0,"IDirectSoundBuffer_GetFormat() should have "
326        "returned the needed size: rc=%s size=%ld\n",DXGetErrorString8(rc),size);
327
328     rc=IDirectSoundBuffer_GetFormat(*dsbo,&wfx,sizeof(wfx),NULL);
329     ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %s\n",
330        DXGetErrorString8(rc));
331     if (rc==DS_OK && winetest_debug > 1) {
332         trace("    Format: %s tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n",
333               is_primary ? "Primary" : "Secondary",
334               wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
335               wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
336     }
337
338     /* DSOUND: Error: Invalid frequency buffer */
339     rc=IDirectSoundBuffer_GetFrequency(*dsbo,0);
340     ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetFrequency() should have "
341        "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc));
342
343     /* DSOUND: Error: Primary buffers don't support CTRLFREQUENCY */
344     rc=IDirectSoundBuffer_GetFrequency(*dsbo,&freq);
345     ok((rc==DS_OK && !is_primary) || (rc==DSERR_CONTROLUNAVAIL&&is_primary) ||
346        (rc==DSERR_CONTROLUNAVAIL&&!(dsbcaps.dwFlags&DSBCAPS_CTRLFREQUENCY)),
347        "IDirectSoundBuffer_GetFrequency() failed: %s\n",DXGetErrorString8(rc));
348     if (rc==DS_OK) {
349         DWORD f = set_frequency?frequency:wfx.nSamplesPerSec;
350         ok(freq==f,"The frequency returned by GetFrequency "
351            "%ld does not match the format %ld\n",freq,f);
352     }
353
354     /* DSOUND: Error: Invalid status pointer */
355     rc=IDirectSoundBuffer_GetStatus(*dsbo,0);
356     ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetStatus() should have "
357        "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc));
358
359     rc=IDirectSoundBuffer_GetStatus(*dsbo,&status);
360     ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %s\n",
361        DXGetErrorString8(rc));
362     ok(status==0,"status=0x%lx instead of 0\n",status);
363
364     if (is_primary) {
365         DSBCAPS new_dsbcaps;
366         /* We must call SetCooperativeLevel to be allowed to call SetFormat */
367         /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
368         rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
369         ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: "
370            "%s\n",DXGetErrorString8(rc));
371         if (rc!=DS_OK)
372             return;
373
374         /* DSOUND: Error: Invalid format pointer */
375         rc=IDirectSoundBuffer_SetFormat(*dsbo,0);
376         ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_SetFormat() should have "
377            "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc));
378
379         init_format(&wfx2,WAVE_FORMAT_PCM,11025,16,2);
380         rc=IDirectSoundBuffer_SetFormat(*dsbo,&wfx2);
381         ok(rc==DS_OK,"IDirectSoundBuffer_SetFormat(%s) failed: %s\n",
382            format_string(&wfx2), DXGetErrorString8(rc));
383
384         /* There is no garantee that SetFormat will actually change the
385          * format to what we asked for. It depends on what the soundcard
386          * supports. So we must re-query the format.
387          */
388         rc=IDirectSoundBuffer_GetFormat(*dsbo,&wfx,sizeof(wfx),NULL);
389         ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %s\n",
390            DXGetErrorString8(rc));
391         if (rc==DS_OK &&
392             (wfx.wFormatTag!=wfx2.wFormatTag ||
393              wfx.nSamplesPerSec!=wfx2.nSamplesPerSec ||
394              wfx.wBitsPerSample!=wfx2.wBitsPerSample ||
395              wfx.nChannels!=wfx2.nChannels)) {
396             trace("Requested format tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n",
397                   wfx2.wFormatTag,wfx2.nSamplesPerSec,wfx2.wBitsPerSample,
398                   wfx2.nChannels,wfx2.nAvgBytesPerSec,wfx2.nBlockAlign);
399             trace("Got tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n",
400                   wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
401                   wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
402         }
403
404         ZeroMemory(&new_dsbcaps, sizeof(new_dsbcaps));
405         new_dsbcaps.dwSize = sizeof(new_dsbcaps);
406         rc=IDirectSoundBuffer_GetCaps(*dsbo,&new_dsbcaps);
407         ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %s\n",
408            DXGetErrorString8(rc));
409         if (rc==DS_OK && winetest_debug > 1) {
410             trace("    new Caps: flags=0x%08lx size=%ld\n",new_dsbcaps.dwFlags,
411                   new_dsbcaps.dwBufferBytes);
412         }
413
414         /* Check for primary buffer size change */
415         ok(new_dsbcaps.dwBufferBytes == dsbcaps.dwBufferBytes,
416            "    buffer size changed after SetFormat() - "
417            "previous size was %lu, current size is %lu\n",
418            dsbcaps.dwBufferBytes, new_dsbcaps.dwBufferBytes);
419
420         /* Check for primary buffer flags change */
421         ok(new_dsbcaps.dwFlags == dsbcaps.dwFlags,
422            "    flags changed after SetFormat() - "
423            "previous flags were %08lx, current flags are %08lx\n",
424            dsbcaps.dwFlags, new_dsbcaps.dwFlags);
425
426         /* Set the CooperativeLevel back to normal */
427         /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
428         rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
429         ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: "
430            "%s\n",DXGetErrorString8(rc));
431     }
432
433     if (play) {
434         play_state_t state;
435         DS3DLISTENER listener_param;
436         LPDIRECTSOUND3DBUFFER buffer=NULL;
437         DS3DBUFFER buffer_param;
438         DWORD start_time,now;
439
440         if (winetest_interactive) {
441             if (set_frequency)
442                 trace("    Playing %g second 440Hz tone at %ldx%dx%d with a "
443                       "frequency of %ld (%ldHz)\n", duration,
444                       wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nChannels,
445                       frequency, (440 * frequency) / wfx.nSamplesPerSec);
446             else
447                 trace("    Playing %g second 440Hz tone at %ldx%dx%d\n", duration,
448                       wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nChannels);
449         }
450
451         if (is_primary) {
452             /* We must call SetCooperativeLevel to be allowed to call Lock */
453             /* DSOUND: Setting DirectSound cooperative level to
454              * DSSCL_WRITEPRIMARY */
455             rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),
456                                                 DSSCL_WRITEPRIMARY);
457             ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_WRITEPRIMARY) "
458                "failed: %s\n",DXGetErrorString8(rc));
459             if (rc!=DS_OK)
460                 return;
461         }
462         if (buffer3d) {
463             LPDIRECTSOUNDBUFFER temp_buffer;
464
465             rc=IDirectSoundBuffer_QueryInterface(*dsbo,&IID_IDirectSound3DBuffer,
466                                                  (LPVOID *)&buffer);
467             ok(rc==DS_OK,"IDirectSoundBuffer_QueryInterface() failed: %s\n",
468                DXGetErrorString8(rc));
469             if (rc!=DS_OK)
470                 return;
471
472             /* check the COM interface */
473             rc=IDirectSoundBuffer_QueryInterface(*dsbo, &IID_IDirectSoundBuffer,
474                                                  (LPVOID *)&temp_buffer);
475             ok(rc==DS_OK && temp_buffer!=NULL,
476                "IDirectSoundBuffer_QueryInterface() failed: %s\n",
477                DXGetErrorString8(rc));
478             ok(temp_buffer==*dsbo,"COM interface broken: %p != %p\n",
479                temp_buffer,*dsbo);
480             ref=IDirectSoundBuffer_Release(temp_buffer);
481             ok(ref==1,"IDirectSoundBuffer_Release() has %d references, "
482                "should have 1\n",ref);
483
484             temp_buffer=NULL;
485             rc=IDirectSound3DBuffer_QueryInterface(*dsbo,
486                                                    &IID_IDirectSoundBuffer,
487                                                    (LPVOID *)&temp_buffer);
488             ok(rc==DS_OK && temp_buffer!=NULL,
489                "IDirectSound3DBuffer_QueryInterface() failed: %s\n",
490                DXGetErrorString8(rc));
491             ok(temp_buffer==*dsbo,"COM interface broken: %p != %p\n",
492                temp_buffer,*dsbo);
493             ref=IDirectSoundBuffer_Release(temp_buffer);
494             ok(ref==1,"IDirectSoundBuffer_Release() has %d references, "
495                "should have 1\n",ref);
496
497             ref=IDirectSoundBuffer_Release(*dsbo);
498             ok(ref==0,"IDirectSoundBuffer_Release() has %d references, "
499                "should have 0\n",ref);
500
501             rc=IDirectSound3DBuffer_QueryInterface(buffer,
502                                                    &IID_IDirectSoundBuffer,
503                                                    (LPVOID *)dsbo);
504             ok(rc==DS_OK && *dsbo!=NULL,"IDirectSound3DBuffer_QueryInterface() "
505                "failed: %s\n",DXGetErrorString8(rc));
506
507             /* DSOUND: Error: Invalid buffer */
508             rc=IDirectSound3DBuffer_GetAllParameters(buffer,0);
509             ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() "
510                "failed: %s\n",DXGetErrorString8(rc));
511
512             ZeroMemory(&buffer_param, sizeof(buffer_param));
513
514             /* DSOUND: Error: Invalid buffer */
515             rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param);
516             ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() "
517                "failed: %s\n",DXGetErrorString8(rc));
518
519             buffer_param.dwSize=sizeof(buffer_param);
520             rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param);
521             ok(rc==DS_OK,"IDirectSound3DBuffer_GetAllParameters() failed: %s\n",
522                DXGetErrorString8(rc));
523         }
524         if (set_volume) {
525             if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) {
526                 LONG val;
527                 rc=IDirectSoundBuffer_GetVolume(*dsbo,&val);
528                 ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %s\n",
529                    DXGetErrorString8(rc));
530
531                 rc=IDirectSoundBuffer_SetVolume(*dsbo,volume);
532                 ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume() failed: %s\n",
533                    DXGetErrorString8(rc));
534             } else {
535                 /* DSOUND: Error: Buffer does not have CTRLVOLUME */
536                 rc=IDirectSoundBuffer_GetVolume(*dsbo,&volume);
537                 ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetVolume() "
538                    "should have returned DSERR_CONTROLUNAVAIL, returned: %s\n",
539                    DXGetErrorString8(rc));
540             }
541         }
542
543         if (set_pan) {
544             if (dsbcaps.dwFlags & DSBCAPS_CTRLPAN) {
545                 LONG val;
546                 rc=IDirectSoundBuffer_GetPan(*dsbo,&val);
547                 ok(rc==DS_OK,"IDirectSoundBuffer_GetPan() failed: %s\n",
548                    DXGetErrorString8(rc));
549
550                 rc=IDirectSoundBuffer_SetPan(*dsbo,pan);
551                 ok(rc==DS_OK,"IDirectSoundBuffer_SetPan() failed: %s\n",
552                    DXGetErrorString8(rc));
553             } else {
554                 /* DSOUND: Error: Buffer does not have CTRLPAN */
555                 rc=IDirectSoundBuffer_GetPan(*dsbo,&pan);
556                 ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetPan() "
557                    "should have returned DSERR_CONTROLUNAVAIL, returned: %s\n",
558                    DXGetErrorString8(rc));
559             }
560         }
561
562         if (set_frequency)
563             state.wave=wave_generate_la(&wfx,(duration*frequency)/wfx.nSamplesPerSec,&state.wave_len);
564         else
565             state.wave=wave_generate_la(&wfx,duration,&state.wave_len);
566
567         state.dsbo=*dsbo;
568         state.wfx=&wfx;
569         state.buffer_size=dsbcaps.dwBufferBytes;
570         state.played=state.written=state.offset=0;
571         buffer_refill(&state,state.buffer_size);
572
573         rc=IDirectSoundBuffer_Play(*dsbo,0,0,DSBPLAY_LOOPING);
574         ok(rc==DS_OK,"IDirectSoundBuffer_Play() failed: %s\n",
575            DXGetErrorString8(rc));
576
577         rc=IDirectSoundBuffer_GetStatus(*dsbo,&status);
578         ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %s\n",
579            DXGetErrorString8(rc));
580         ok(status==(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING),
581            "GetStatus: bad status: %lx\n",status);
582
583         if (listener) {
584             ZeroMemory(&listener_param,sizeof(listener_param));
585             listener_param.dwSize=sizeof(listener_param);
586             rc=IDirectSound3DListener_GetAllParameters(listener,
587                                                        &listener_param);
588             ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() "
589                "failed: %s\n",DXGetErrorString8(rc));
590             if (move_listener) {
591                 listener_param.vPosition.x = -5.0;
592                 listener_param.vVelocity.x = 10.0/duration;
593             }
594             rc=IDirectSound3DListener_SetAllParameters(listener,
595                                                        &listener_param,
596                                                        DS3D_IMMEDIATE);
597             ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %s\n",
598                DXGetErrorString8(rc));
599         }
600         if (buffer3d) {
601             if (move_sound) {
602                 buffer_param.vPosition.x = 100.0;
603                 buffer_param.vVelocity.x = -200.0/duration;
604             }
605             buffer_param.flMinDistance = 10;
606             rc=IDirectSound3DBuffer_SetAllParameters(buffer,&buffer_param,
607                                                      DS3D_IMMEDIATE);
608             ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %s\n",
609                DXGetErrorString8(rc));
610         }
611
612         start_time=GetTickCount();
613         while (buffer_service(&state)) {
614             WaitForSingleObject(GetCurrentProcess(),TIME_SLICE);
615             now=GetTickCount();
616             if (listener && move_listener) {
617                 listener_param.vPosition.x = -5.0+10.0*(now-start_time)/
618                     1000/duration;
619                 if (winetest_debug>2)
620                     trace("listener position=%g\n",listener_param.vPosition.x);
621                 rc=IDirectSound3DListener_SetPosition(listener,
622                     listener_param.vPosition.x,listener_param.vPosition.y,
623                     listener_param.vPosition.z,DS3D_IMMEDIATE);
624                 ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: "
625                    "%s\n",DXGetErrorString8(rc));
626             }
627             if (buffer3d && move_sound) {
628                 buffer_param.vPosition.x = 100-200.0*(now-start_time)/
629                     1000/duration;
630                 if (winetest_debug>2)
631                     trace("sound position=%g\n",buffer_param.vPosition.x);
632                 rc=IDirectSound3DBuffer_SetPosition(buffer,
633                     buffer_param.vPosition.x,buffer_param.vPosition.y,
634                     buffer_param.vPosition.z,DS3D_IMMEDIATE);
635                 ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %s\n",
636                    DXGetErrorString8(rc));
637             }
638         }
639         /* Check the sound duration was within 10% of the expected value */
640         now=GetTickCount();
641         ok(fabs(1000*duration-now+start_time)<=100*duration,
642            "The sound played for %ld ms instead of %g ms\n",
643            now-start_time,1000*duration);
644
645         free(state.wave);
646         if (is_primary) {
647             /* Set the CooperativeLevel back to normal */
648             /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
649             rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
650             ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) "
651                "failed: %s\n",DXGetErrorString8(rc));
652         }
653         if (buffer3d) {
654             ref=IDirectSound3DBuffer_Release(buffer);
655             ok(ref==0,"IDirectSound3DBuffer_Release() has %d references, "
656                "should have 0\n",ref);
657         }
658     }
659 }
660
661 static HRESULT test_secondary(LPGUID lpGuid, int play,
662                               int has_3d, int has_3dbuffer,
663                               int has_listener, int has_duplicate,
664                               int move_listener, int move_sound)
665 {
666     HRESULT rc;
667     LPDIRECTSOUND dso=NULL;
668     LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL;
669     LPDIRECTSOUND3DLISTENER listener=NULL;
670     DSBUFFERDESC bufdesc;
671     WAVEFORMATEX wfx, wfx1;
672     int ref;
673
674     /* Create the DirectSound object */
675     rc=DirectSoundCreate(lpGuid,&dso,NULL);
676     ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %s\n",
677        DXGetErrorString8(rc));
678     if (rc!=DS_OK)
679         return rc;
680
681     /* We must call SetCooperativeLevel before creating primary buffer */
682     /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
683     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
684     ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: "
685        "%s\n",DXGetErrorString8(rc));
686     if (rc!=DS_OK)
687         goto EXIT;
688
689     ZeroMemory(&bufdesc, sizeof(bufdesc));
690     bufdesc.dwSize=sizeof(bufdesc);
691     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
692     if (has_3d)
693         bufdesc.dwFlags|=DSBCAPS_CTRL3D;
694     else
695         bufdesc.dwFlags|=(DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN);
696     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
697     ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL),
698        "IDirectSound_CreateSoundBuffer() failed to create a %sprimary buffer: "
699        "%s\n",has_3d?"3D ":"", DXGetErrorString8(rc));
700     if (rc==DSERR_CONTROLUNAVAIL)
701         trace("  No Primary\n");
702     else if (rc==DS_OK && primary!=NULL) {
703         rc=IDirectSoundBuffer_GetFormat(primary,&wfx1,sizeof(wfx1),NULL);
704         ok(rc==DS_OK,"IDirectSoundBuffer8_Getformat() failed: %s\n",
705            DXGetErrorString8(rc));
706         if (rc!=DS_OK)
707             goto EXIT1;
708
709         if (has_listener) {
710             rc=IDirectSoundBuffer_QueryInterface(primary,
711                                                  &IID_IDirectSound3DListener,
712                                                  (void **)&listener);
713             ok(rc==DS_OK && listener!=NULL,
714                "IDirectSoundBuffer_QueryInterface() failed to get a 3D "
715                "listener: %s\n",DXGetErrorString8(rc));
716             ref=IDirectSoundBuffer_Release(primary);
717             ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
718                "should have 0\n",ref);
719             if (rc==DS_OK && listener!=NULL) {
720                 DS3DLISTENER listener_param;
721                 ZeroMemory(&listener_param,sizeof(listener_param));
722                 /* DSOUND: Error: Invalid buffer */
723                 rc=IDirectSound3DListener_GetAllParameters(listener,0);
724                 ok(rc==DSERR_INVALIDPARAM,
725                    "IDirectSound3dListener_GetAllParameters() should have "
726                    "returned DSERR_INVALIDPARAM, returned: %s\n",
727                    DXGetErrorString8(rc));
728
729                 /* DSOUND: Error: Invalid buffer */
730                 rc=IDirectSound3DListener_GetAllParameters(listener,
731                                                            &listener_param);
732                 ok(rc==DSERR_INVALIDPARAM,
733                    "IDirectSound3dListener_GetAllParameters() should have "
734                    "returned DSERR_INVALIDPARAM, returned: %s\n",
735                    DXGetErrorString8(rc));
736
737                 listener_param.dwSize=sizeof(listener_param);
738                 rc=IDirectSound3DListener_GetAllParameters(listener,
739                                                            &listener_param);
740                 ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() "
741                    "failed: %s\n",DXGetErrorString8(rc));
742             }
743             else
744                 goto EXIT;
745         }
746
747         init_format(&wfx,WAVE_FORMAT_PCM,22050,16,2);
748         secondary=NULL;
749         ZeroMemory(&bufdesc, sizeof(bufdesc));
750         bufdesc.dwSize=sizeof(bufdesc);
751         bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
752         if (has_3d)
753             bufdesc.dwFlags|=DSBCAPS_CTRL3D;
754         else
755             bufdesc.dwFlags|=
756                 (DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN);
757         bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000,
758                                     wfx.nBlockAlign);
759         bufdesc.lpwfxFormat=&wfx;
760         if (winetest_interactive) {
761             trace("  Testing a %s%ssecondary buffer %s%s%s%sat %ldx%dx%d "
762                   "with a primary buffer at %ldx%dx%d\n",
763                   has_3dbuffer?"3D ":"",
764                   has_duplicate?"duplicated ":"",
765                   listener!=NULL||move_sound?"with ":"",
766                   move_listener?"moving ":"",
767                   listener!=NULL?"listener ":"",
768                   listener&&move_sound?"and moving sound ":move_sound?
769                   "moving sound ":"",
770                   wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,
771                   wfx1.nSamplesPerSec,wfx1.wBitsPerSample,wfx1.nChannels);
772         }
773         rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
774         ok(rc==DS_OK && secondary!=NULL,"IDirectSound_CreateSoundBuffer() "
775            "failed to create a %s%ssecondary buffer %s%s%s%sat %ldx%dx%d (%s): %s\n",
776            has_3dbuffer?"3D ":"", has_duplicate?"duplicated ":"",
777            listener!=NULL||move_sound?"with ":"", move_listener?"moving ":"",
778            listener!=NULL?"listener ":"",
779            listener&&move_sound?"and moving sound ":move_sound?
780            "moving sound ":"",
781            wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,
782            getDSBCAPS(bufdesc.dwFlags),DXGetErrorString8(rc));
783         if (rc==DS_OK && secondary!=NULL) {
784             if (!has_3d) {
785                 LONG refvol,vol,refpan,pan;
786
787                 /* Check the initial secondary buffer's volume and pan */
788                 rc=IDirectSoundBuffer_GetVolume(secondary,&vol);
789                 ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(secondary) failed: "
790                    "%s\n",DXGetErrorString8(rc));
791                 ok(vol==0,"wrong volume for a new secondary buffer: %ld\n",vol);
792                 rc=IDirectSoundBuffer_GetPan(secondary,&pan);
793                 ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(secondary) failed: "
794                    "%s\n",DXGetErrorString8(rc));
795                 ok(pan==0,"wrong pan for a new secondary buffer: %ld\n",pan);
796
797                 /* Check that changing the secondary buffer's volume and pan
798                  * does not impact the primary buffer's volume and pan
799                  */
800                 rc=IDirectSoundBuffer_GetVolume(primary,&refvol);
801                 ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: "
802                    "%s\n",DXGetErrorString8(rc));
803                 rc=IDirectSoundBuffer_GetPan(primary,&refpan);
804                 ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %s\n",
805                    DXGetErrorString8(rc));
806
807                 rc=IDirectSoundBuffer_SetVolume(secondary,-1000);
808                 ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: "
809                    "%s\n",DXGetErrorString8(rc));
810                 rc=IDirectSoundBuffer_GetVolume(secondary,&vol);
811                 ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: "
812                    "%s\n",DXGetErrorString8(rc));
813                 ok(vol==-1000,"secondary: wrong volume %ld instead of -1000\n",
814                    vol);
815                 rc=IDirectSoundBuffer_SetPan(secondary,-1000);
816                 ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: "
817                    "%s\n",DXGetErrorString8(rc));
818                 rc=IDirectSoundBuffer_GetPan(secondary,&pan);
819                 ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: "
820                    "%s\n",DXGetErrorString8(rc));
821                 ok(pan==-1000,"secondary: wrong pan %ld instead of -1000\n",
822                    pan);
823
824                 rc=IDirectSoundBuffer_GetVolume(primary,&vol);
825                 ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: "
826                    "%s\n",DXGetErrorString8(rc));
827                 ok(vol==refvol,"The primary volume changed from %ld to %ld\n",
828                    refvol,vol);
829                 rc=IDirectSoundBuffer_GetPan(primary,&pan);
830                 ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %s\n",
831                    DXGetErrorString8(rc));
832                 ok(pan==refpan,"The primary pan changed from %ld to %ld\n",
833                    refpan,pan);
834
835                 rc=IDirectSoundBuffer_SetVolume(secondary,0);
836                 ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: "
837                    "%s\n",DXGetErrorString8(rc));
838                 rc=IDirectSoundBuffer_SetPan(secondary,0);
839                 ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: "
840                    "%s\n",DXGetErrorString8(rc));
841             }
842             if (has_duplicate) {
843                 LPDIRECTSOUNDBUFFER duplicated=NULL;
844
845                 /* DSOUND: Error: Invalid source buffer */
846                 rc=IDirectSound_DuplicateSoundBuffer(dso,0,0);
847                 ok(rc==DSERR_INVALIDPARAM,
848                    "IDirectSound_DuplicateSoundBuffer() should have returned "
849                    "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc));
850
851                 /* DSOUND: Error: Invalid dest buffer */
852                 rc=IDirectSound_DuplicateSoundBuffer(dso,secondary,0);
853                 ok(rc==DSERR_INVALIDPARAM,
854                    "IDirectSound_DuplicateSoundBuffer() should have returned "
855                    "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc));
856
857                 /* DSOUND: Error: Invalid source buffer */
858                 rc=IDirectSound_DuplicateSoundBuffer(dso,0,&duplicated);
859                 ok(rc==DSERR_INVALIDPARAM,
860                   "IDirectSound_DuplicateSoundBuffer() should have returned "
861                   "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc));
862
863                 duplicated=NULL;
864                 rc=IDirectSound_DuplicateSoundBuffer(dso,secondary,
865                                                      &duplicated);
866                 ok(rc==DS_OK && duplicated!=NULL,
867                    "IDirectSound_DuplicateSoundBuffer() failed to duplicate "
868                    "a secondary buffer: %s\n",DXGetErrorString8(rc));
869
870                 if (rc==DS_OK && duplicated!=NULL) {
871                     ref=IDirectSoundBuffer_Release(secondary);
872                     ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d "
873                       "references, should have 0\n",ref);
874                     secondary=duplicated;
875                 }
876             }
877
878             if (rc==DS_OK && secondary!=NULL) {
879                 double duration;
880                 duration=(move_listener || move_sound?4.0:1.0);
881                 test_buffer(dso,&secondary,0,FALSE,0,FALSE,0,
882                             winetest_interactive,duration,has_3dbuffer,
883                             listener,move_listener,move_sound,FALSE,0);
884                 ref=IDirectSoundBuffer_Release(secondary);
885                 ok(ref==0,"IDirectSoundBuffer_Release() %s has %d references, "
886                    "should have 0\n",has_duplicate?"duplicated":"secondary",
887                    ref);
888             }
889         }
890     }
891 EXIT1:
892     if (has_listener) {
893         ref=IDirectSound3DListener_Release(listener);
894         ok(ref==0,"IDirectSound3dListener_Release() listener has %d "
895            "references, should have 0\n",ref);
896     } else {
897         ref=IDirectSoundBuffer_Release(primary);
898         ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
899            "should have 0\n",ref);
900     }
901
902     /* Set the CooperativeLevel back to normal */
903     /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
904     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
905     ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %s\n",
906        DXGetErrorString8(rc));
907
908 EXIT:
909     ref=IDirectSound_Release(dso);
910     ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
911     if (ref!=0)
912         return DSERR_GENERIC;
913
914     return rc;
915 }
916
917 static HRESULT test_for_driver(LPGUID lpGuid)
918 {
919     HRESULT rc;
920     LPDIRECTSOUND dso=NULL;
921     int ref;
922
923     /* Create the DirectSound object */
924     rc=DirectSoundCreate(lpGuid,&dso,NULL);
925     ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
926        "DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc));
927     if (rc!=DS_OK)
928         return rc;
929
930     ref=IDirectSound_Release(dso);
931     ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
932     if (ref!=0)
933         return DSERR_GENERIC;
934
935     return rc;
936 }
937
938 static HRESULT test_primary(LPGUID lpGuid)
939 {
940     HRESULT rc;
941     LPDIRECTSOUND dso=NULL;
942     LPDIRECTSOUNDBUFFER primary=NULL;
943     DSBUFFERDESC bufdesc;
944     DSCAPS dscaps;
945     int ref, i;
946
947     /* Create the DirectSound object */
948     rc=DirectSoundCreate(lpGuid,&dso,NULL);
949     ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %s\n",
950        DXGetErrorString8(rc));
951     if (rc!=DS_OK)
952         return rc;
953
954     /* Get the device capabilities */
955     ZeroMemory(&dscaps, sizeof(dscaps));
956     dscaps.dwSize=sizeof(dscaps);
957     rc=IDirectSound_GetCaps(dso,&dscaps);
958     ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc));
959     if (rc!=DS_OK)
960         goto EXIT;
961
962     /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
963     /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
964     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
965     ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: "
966        "%s\n",DXGetErrorString8(rc));
967     if (rc!=DS_OK)
968         goto EXIT;
969
970     /* Testing the primary buffer */
971     primary=NULL;
972     ZeroMemory(&bufdesc, sizeof(bufdesc));
973     bufdesc.dwSize=sizeof(bufdesc);
974     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN;
975     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
976     ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL),
977        "IDirectSound_CreateSoundBuffer() failed to create a primary buffer: "
978        "%s\n",DXGetErrorString8(rc));
979     if (rc==DSERR_CONTROLUNAVAIL)
980         trace("  No Primary\n");
981     else if (rc==DS_OK && primary!=NULL) {
982         test_buffer(dso,&primary,1,TRUE,0,TRUE,0,winetest_interactive &&
983                     !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,NULL,0,0,
984                     FALSE,0);
985         if (winetest_interactive) {
986             LONG volume,pan;
987
988             volume = DSBVOLUME_MAX;
989             for (i = 0; i < 6; i++) {
990                 test_buffer(dso,&primary,1,TRUE,volume,TRUE,0,
991                             winetest_interactive &&
992                             !(dscaps.dwFlags & DSCAPS_EMULDRIVER),
993                             1.0,0,NULL,0,0,FALSE,0);
994                 volume -= ((DSBVOLUME_MAX-DSBVOLUME_MIN) / 40);
995             }
996
997             pan = DSBPAN_LEFT;
998             for (i = 0; i < 7; i++) {
999                 test_buffer(dso,&primary,1,TRUE,0,TRUE,pan,
1000                             winetest_interactive &&
1001                             !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0,FALSE,0);
1002                 pan += ((DSBPAN_RIGHT-DSBPAN_LEFT) / 6);
1003             }
1004         }
1005         ref=IDirectSoundBuffer_Release(primary);
1006         ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
1007            "should have 0\n",ref);
1008     }
1009
1010     /* Set the CooperativeLevel back to normal */
1011     /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
1012     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
1013     ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %s\n",
1014        DXGetErrorString8(rc));
1015
1016 EXIT:
1017     ref=IDirectSound_Release(dso);
1018     ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
1019     if (ref!=0)
1020         return DSERR_GENERIC;
1021
1022     return rc;
1023 }
1024
1025 static HRESULT test_primary_3d(LPGUID lpGuid)
1026 {
1027     HRESULT rc;
1028     LPDIRECTSOUND dso=NULL;
1029     LPDIRECTSOUNDBUFFER primary=NULL;
1030     DSBUFFERDESC bufdesc;
1031     DSCAPS dscaps;
1032     int ref;
1033
1034     /* Create the DirectSound object */
1035     rc=DirectSoundCreate(lpGuid,&dso,NULL);
1036     ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %s\n",
1037        DXGetErrorString8(rc));
1038     if (rc!=DS_OK)
1039         return rc;
1040
1041     /* Get the device capabilities */
1042     ZeroMemory(&dscaps, sizeof(dscaps));
1043     dscaps.dwSize=sizeof(dscaps);
1044     rc=IDirectSound_GetCaps(dso,&dscaps);
1045     ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc));
1046     if (rc!=DS_OK)
1047         goto EXIT;
1048
1049     /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
1050     /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
1051     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
1052     ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: "
1053        "%s\n",DXGetErrorString8(rc));
1054     if (rc!=DS_OK)
1055         goto EXIT;
1056
1057     primary=NULL;
1058     ZeroMemory(&bufdesc, sizeof(bufdesc));
1059     bufdesc.dwSize=sizeof(bufdesc);
1060     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
1061     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
1062     ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() failed "
1063        "to create a primary buffer: %s\n",DXGetErrorString8(rc));
1064     if (rc==DS_OK && primary!=NULL) {
1065         ref=IDirectSoundBuffer_Release(primary);
1066         ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
1067            "should have 0\n",ref);
1068         primary=NULL;
1069         ZeroMemory(&bufdesc, sizeof(bufdesc));
1070         bufdesc.dwSize=sizeof(bufdesc);
1071         bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
1072         rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
1073         ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() "
1074            "failed to create a 3D primary buffer: %s\n",DXGetErrorString8(rc));
1075         if (rc==DS_OK && primary!=NULL) {
1076             test_buffer(dso,&primary,1,FALSE,0,FALSE,0,winetest_interactive &&
1077                         !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0,
1078                         FALSE,0);
1079             ref=IDirectSoundBuffer_Release(primary);
1080             ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
1081                "should have 0\n",ref);
1082         }
1083     }
1084     /* Set the CooperativeLevel back to normal */
1085     /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
1086     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
1087     ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %s\n",
1088        DXGetErrorString8(rc));
1089
1090 EXIT:
1091     ref=IDirectSound_Release(dso);
1092     ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
1093     if (ref!=0)
1094         return DSERR_GENERIC;
1095
1096     return rc;
1097 }
1098
1099 static HRESULT test_primary_3d_with_listener(LPGUID lpGuid)
1100 {
1101     HRESULT rc;
1102     LPDIRECTSOUND dso=NULL;
1103     LPDIRECTSOUNDBUFFER primary=NULL;
1104     DSBUFFERDESC bufdesc;
1105     DSCAPS dscaps;
1106     int ref;
1107
1108     /* Create the DirectSound object */
1109     rc=DirectSoundCreate(lpGuid,&dso,NULL);
1110     ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %s\n",
1111        DXGetErrorString8(rc));
1112     if (rc!=DS_OK)
1113         return rc;
1114
1115     /* Get the device capabilities */
1116     ZeroMemory(&dscaps, sizeof(dscaps));
1117     dscaps.dwSize=sizeof(dscaps);
1118     rc=IDirectSound_GetCaps(dso,&dscaps);
1119     ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc));
1120     if (rc!=DS_OK)
1121         goto EXIT;
1122
1123     /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
1124     /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
1125     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
1126     ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: "
1127        "%s\n",DXGetErrorString8(rc));
1128     if (rc!=DS_OK)
1129         goto EXIT;
1130     primary=NULL;
1131     ZeroMemory(&bufdesc, sizeof(bufdesc));
1132     bufdesc.dwSize=sizeof(bufdesc);
1133     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
1134     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
1135     ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() failed "
1136        "to create a 3D primary buffer: %s\n",DXGetErrorString8(rc));
1137     if (rc==DS_OK && primary!=NULL) {
1138         LPDIRECTSOUND3DLISTENER listener=NULL;
1139         rc=IDirectSoundBuffer_QueryInterface(primary,
1140             &IID_IDirectSound3DListener,(void **)&listener);
1141         ok(rc==DS_OK && listener!=NULL,"IDirectSoundBuffer_QueryInterface() "
1142            "failed to get a 3D listener: %s\n",DXGetErrorString8(rc));
1143         if (rc==DS_OK && listener!=NULL) {
1144             LPDIRECTSOUNDBUFFER temp_buffer=NULL;
1145
1146             /* Checking the COM interface */
1147             rc=IDirectSoundBuffer_QueryInterface(primary,
1148                 &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer);
1149             ok(rc==DS_OK && temp_buffer!=NULL,
1150                "IDirectSoundBuffer_QueryInterface() failed: %s\n",
1151                DXGetErrorString8(rc));
1152             ok(temp_buffer==primary,
1153                "COM interface broken: %p != %p\n",
1154                temp_buffer,primary);
1155             if (rc==DS_OK && temp_buffer!=NULL) {
1156                 ref=IDirectSoundBuffer_Release(temp_buffer);
1157                 ok(ref==1,"IDirectSoundBuffer_Release() has %d references, "
1158                    "should have 1\n",ref);
1159
1160                 temp_buffer=NULL;
1161                 rc=IDirectSound3DListener_QueryInterface(listener,
1162                     &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer);
1163                 ok(rc==DS_OK && temp_buffer!=NULL,
1164                    "IDirectSoundBuffer_QueryInterface() failed: %s\n",
1165                    DXGetErrorString8(rc));
1166                 ok(temp_buffer==primary,
1167                    "COM interface broken: %p != %p\n",
1168                    temp_buffer,primary);
1169                 ref=IDirectSoundBuffer_Release(temp_buffer);
1170                 ok(ref==1,"IDirectSoundBuffer_Release() has %d references, "
1171                    "should have 1\n",ref);
1172
1173                 /* Testing the buffer */
1174                 test_buffer(dso,&primary,1,FALSE,0,FALSE,0,
1175                             winetest_interactive &&
1176                             !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,
1177                             listener,0,0,FALSE,0);
1178             }
1179
1180             /* Testing the reference counting */
1181             ref=IDirectSound3DListener_Release(listener);
1182             ok(ref==0,"IDirectSound3DListener_Release() listener has %d "
1183                "references, should have 0\n",ref);
1184         }
1185
1186         /* Testing the reference counting */
1187         ref=IDirectSoundBuffer_Release(primary);
1188         ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
1189            "should have 0\n",ref);
1190     }
1191
1192 EXIT:
1193     ref=IDirectSound_Release(dso);
1194     ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
1195     if (ref!=0)
1196 return DSERR_GENERIC;
1197
1198     return rc;
1199 }
1200
1201 static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
1202                                    LPCSTR lpcstrModule, LPVOID lpContext)
1203 {
1204     HRESULT rc;
1205     trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule);
1206
1207     rc = test_for_driver(lpGuid);
1208     if (rc == DSERR_NODRIVER) {
1209         trace("  No Driver\n");
1210         return 1;
1211     } else if (rc == DSERR_ALLOCATED) {
1212         trace("  Already In Use\n");
1213         return 1;
1214     } else if (rc == E_FAIL) {
1215         trace("  No Device\n");
1216         return 1;
1217     }
1218
1219     trace("  Testing the primary buffer\n");
1220     test_primary(lpGuid);
1221
1222     trace("  Testing 3D primary buffer\n");
1223     test_primary_3d(lpGuid);
1224
1225     trace("  Testing 3D primary buffer with listener\n");
1226     test_primary_3d_with_listener(lpGuid);
1227
1228     /* Testing secondary buffers */
1229     test_secondary(lpGuid,winetest_interactive,0,0,0,0,0,0);
1230     test_secondary(lpGuid,winetest_interactive,0,0,0,1,0,0);
1231
1232     /* Testing 3D secondary buffers */
1233     test_secondary(lpGuid,winetest_interactive,1,0,0,0,0,0);
1234     test_secondary(lpGuid,winetest_interactive,1,1,0,0,0,0);
1235     test_secondary(lpGuid,winetest_interactive,1,1,0,1,0,0);
1236     test_secondary(lpGuid,winetest_interactive,1,0,1,0,0,0);
1237     test_secondary(lpGuid,winetest_interactive,1,0,1,1,0,0);
1238     test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,0);
1239     test_secondary(lpGuid,winetest_interactive,1,1,1,1,0,0);
1240     test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,0);
1241     test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,1);
1242     test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,1);
1243
1244     return 1;
1245 }
1246
1247 static void ds3d_tests(void)
1248 {
1249     HRESULT rc;
1250     rc=DirectSoundEnumerateA(&dsenum_callback,NULL);
1251     ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %s\n",DXGetErrorString8(rc));
1252 }
1253
1254 START_TEST(ds3d)
1255 {
1256     CoInitialize(NULL);
1257
1258     trace("DLL Version: %s\n", get_file_version("dsound.dll"));
1259
1260     ds3d_tests();
1261
1262     CoUninitialize();
1263 }