~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/dsound/tests/ds3d.c

Version: ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 24  */
 25 
 26 #include <windows.h>
 27 
 28 #include <math.h>
 29 
 30 #include "wine/test.h"
 31 #include "dsound.h"
 32 #include "mmreg.h"
 33 #include "dsound_test.h"
 34 
 35 #define PI 3.14159265358979323846
 36 
 37 
 38 static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL;
 39 static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID,LPDIRECTSOUND*,
 40     LPUNKNOWN)=NULL;
 41 
 42 char* wave_generate_la(WAVEFORMATEX* wfx, double duration, DWORD* size)
 43 {
 44     int i;
 45     int nb_samples;
 46     char* buf;
 47     char* b;
 48 
 49     nb_samples=(int)(duration*wfx->nSamplesPerSec);
 50     *size=nb_samples*wfx->nBlockAlign;
 51     b=buf=malloc(*size);
 52     for (i=0;i<nb_samples;i++) {
 53         double y=sin(440.0*2*PI*i/wfx->nSamplesPerSec);
 54         if (wfx->wBitsPerSample==8) {
 55             unsigned char sample=(unsigned char)((double)127.5*(y+1.0));
 56             *b++=sample;
 57             if (wfx->nChannels==2)
 58                 *b++=sample;
 59         } else if (wfx->wBitsPerSample == 16) {
 60             signed short sample=(signed short)((double)32767.5*y-0.5);
 61             b[0]=sample & 0xff;
 62             b[1]=sample >> 8;
 63             b+=2;
 64             if (wfx->nChannels==2) {
 65                 b[0]=sample & 0xff;
 66                 b[1]=sample >> 8;
 67                 b+=2;
 68             }
 69         } else if (wfx->wBitsPerSample == 24) {
 70             signed int sample=(signed int)((double)8388607.5*y-0.5);
 71             b[0]=sample & 0xff;
 72             b[1]=(sample >> 8)&0xff;
 73             b[2]=sample >> 16;
 74             b+=3;
 75             if (wfx->nChannels==2) {
 76                 b[0]=sample & 0xff;
 77                 b[1]=(sample >> 8)&0xff;
 78                 b[2]=sample >> 16;
 79                 b+=3;
 80             }
 81         } else if (wfx->wBitsPerSample == 32) {
 82             signed int sample=(signed int)((double)2147483647.5*y-0.5);
 83             b[0]=sample & 0xff;
 84             b[1]=(sample >> 8)&0xff;
 85             b[2]=(sample >> 16)&0xff;
 86             b[3]=sample >> 24;
 87             b+=4;
 88             if (wfx->nChannels==2) {
 89                 b[0]=sample & 0xff;
 90                 b[1]=(sample >> 8)&0xff;
 91                 b[2]=(sample >> 16)&0xff;
 92                 b[3]=sample >> 24;
 93                 b+=4;
 94             }
 95         }
 96     }
 97     return buf;
 98 }
 99 
100 const char * getDSBCAPS(DWORD xmask) {
101     static struct {
102         DWORD   mask;
103         const char    *name;
104     } flags[] = {
105 #define FE(x) { x, #x },
106         FE(DSBCAPS_PRIMARYBUFFER)
107         FE(DSBCAPS_STATIC)
108         FE(DSBCAPS_LOCHARDWARE)
109         FE(DSBCAPS_LOCSOFTWARE)
110         FE(DSBCAPS_CTRL3D)
111         FE(DSBCAPS_CTRLFREQUENCY)
112         FE(DSBCAPS_CTRLPAN)
113         FE(DSBCAPS_CTRLVOLUME)
114         FE(DSBCAPS_CTRLPOSITIONNOTIFY)
115         FE(DSBCAPS_STICKYFOCUS)
116         FE(DSBCAPS_GLOBALFOCUS)
117         FE(DSBCAPS_GETCURRENTPOSITION2)
118         FE(DSBCAPS_MUTE3DATMAXDISTANCE)
119 #undef FE
120     };
121     static char buffer[512];
122     unsigned int i;
123     BOOL first = TRUE;
124 
125     buffer[0] = 0;
126 
127     for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++) {
128         if ((flags[i].mask & xmask) == flags[i].mask) {
129             if (first)
130                 first = FALSE;
131             else
132                 strcat(buffer, "|");
133             strcat(buffer, flags[i].name);
134         }
135     }
136 
137     return buffer;
138 }
139 
140 HWND get_hwnd(void)
141 {
142     HWND hwnd=GetForegroundWindow();
143     if (!hwnd)
144         hwnd=GetDesktopWindow();
145     return hwnd;
146 }
147 
148 void init_format(WAVEFORMATEX* wfx, int format, int rate, int depth,
149                  int channels)
150 {
151     wfx->wFormatTag=format;
152     wfx->nChannels=channels;
153     wfx->wBitsPerSample=depth;
154     wfx->nSamplesPerSec=rate;
155     wfx->nBlockAlign=wfx->nChannels*wfx->wBitsPerSample/8;
156     /* FIXME: Shouldn't this test be if (format!=WAVE_FORMAT_PCM) */
157     if (wfx->nBlockAlign==0)
158     {
159         /* align compressed formats to byte boundary */
160         wfx->nBlockAlign=1;
161     }
162     wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nBlockAlign;
163     wfx->cbSize=0;
164 }
165 
166 typedef struct {
167     char* wave;
168     DWORD wave_len;
169 
170     LPDIRECTSOUNDBUFFER dsbo;
171     LPWAVEFORMATEX wfx;
172     DWORD buffer_size;
173     DWORD written;
174     DWORD played;
175     DWORD offset;
176 } play_state_t;
177 
178 static int buffer_refill(play_state_t* state, DWORD size)
179 {
180     LPVOID ptr1,ptr2;
181     DWORD len1,len2;
182     HRESULT rc;
183 
184     if (size>state->wave_len-state->written)
185         size=state->wave_len-state->written;
186 
187     rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
188                                &ptr1,&len1,&ptr2,&len2,0);
189     ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %08x\n", rc);
190     if (rc!=DS_OK)
191         return -1;
192 
193     memcpy(ptr1,state->wave+state->written,len1);
194     state->written+=len1;
195     if (ptr2!=NULL) {
196         memcpy(ptr2,state->wave+state->written,len2);
197         state->written+=len2;
198     }
199     state->offset=state->written % state->buffer_size;
200     /* some apps blindly pass &ptr1 instead of ptr1 */
201     rc=IDirectSoundBuffer_Unlock(state->dsbo,&ptr1,len1,ptr2,len2);
202     ok(rc==DSERR_INVALIDPARAM, "IDDirectSoundBuffer_Unlock(): expected %08x got %08x, %p %p\n",DSERR_INVALIDPARAM, rc, &ptr1, ptr1);
203     rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2);
204     ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %08x\n", rc);
205     if (rc!=DS_OK)
206         return -1;
207     return size;
208 }
209 
210 static int buffer_silence(play_state_t* state, DWORD size)
211 {
212     LPVOID ptr1,ptr2;
213     DWORD len1,len2;
214     HRESULT rc;
215     BYTE s;
216 
217     rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
218                                &ptr1,&len1,&ptr2,&len2,0);
219     ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %08x\n", rc);
220     if (rc!=DS_OK)
221         return -1;
222 
223     s=(state->wfx->wBitsPerSample==8?0x80:0);
224     memset(ptr1,s,len1);
225     if (ptr2!=NULL) {
226         memset(ptr2,s,len2);
227     }
228     state->offset=(state->offset+size) % state->buffer_size;
229     rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2);
230     ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %08x\n", rc);
231     if (rc!=DS_OK)
232         return -1;
233     return size;
234 }
235 
236 static int buffer_service(play_state_t* state)
237 {
238     DWORD last_play_pos,play_pos,buf_free;
239     HRESULT rc;
240 
241     rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,NULL);
242     ok(rc==DS_OK,"IDirectSoundBuffer_GetCurrentPosition() failed: %08x\n", rc);
243     if (rc!=DS_OK) {
244         goto STOP;
245     }
246 
247     /* Update the amount played */
248     last_play_pos=state->played % state->buffer_size;
249     if (play_pos<last_play_pos)
250         state->played+=state->buffer_size-last_play_pos+play_pos;
251     else
252         state->played+=play_pos-last_play_pos;
253 
254     if (winetest_debug > 1)
255         trace("buf size=%d last_play_pos=%d play_pos=%d played=%d / %d\n",
256               state->buffer_size,last_play_pos,play_pos,state->played,
257               state->wave_len);
258 
259     if (state->played>state->wave_len)
260     {
261         /* Everything has been played */
262         goto STOP;
263     }
264 
265     /* Refill the buffer */
266     if (state->offset<=play_pos)
267         buf_free=play_pos-state->offset;
268     else
269         buf_free=state->buffer_size-state->offset+play_pos;
270 
271     if (winetest_debug > 1)
272         trace("offset=%d free=%d written=%d / %d\n",
273               state->offset,buf_free,state->written,state->wave_len);
274     if (buf_free==0)
275         return 1;
276 
277     if (state->written<state->wave_len)
278     {
279         int w=buffer_refill(state,buf_free);
280         if (w==-1)
281             goto STOP;
282         buf_free-=w;
283         if (state->written==state->wave_len && winetest_debug > 1)
284             trace("last sound byte at %d\n",
285                   (state->written % state->buffer_size));
286     }
287 
288     if (buf_free>0) {
289         /* Fill with silence */
290         if (winetest_debug > 1)
291             trace("writing %d bytes of silence\n",buf_free);
292         if (buffer_silence(state,buf_free)==-1)
293             goto STOP;
294     }
295     return 1;
296 
297 STOP:
298     if (winetest_debug > 1)
299         trace("stopping playback\n");
300     rc=IDirectSoundBuffer_Stop(state->dsbo);
301     ok(rc==DS_OK,"IDirectSoundBuffer_Stop() failed: %08x\n", rc);
302     return 0;
303 }
304 
305 void test_buffer(LPDIRECTSOUND dso, LPDIRECTSOUNDBUFFER *dsbo,
306                  BOOL is_primary, BOOL set_volume, LONG volume,
307                  BOOL set_pan, LONG pan, BOOL play, double duration,
308                  BOOL buffer3d, LPDIRECTSOUND3DLISTENER listener,
309                  BOOL move_listener, BOOL move_sound,
310                  BOOL set_frequency, DWORD frequency)
311 {
312     HRESULT rc;
313     DSBCAPS dsbcaps;
314     WAVEFORMATEX wfx,wfx2;
315     DWORD size,status,freq;
316     int ref;
317 
318     if (set_frequency) {
319         rc=IDirectSoundBuffer_SetFrequency(*dsbo,frequency);
320         ok(rc==DS_OK||rc==DSERR_CONTROLUNAVAIL,
321            "IDirectSoundBuffer_SetFrequency() failed to set frequency %08x\n",rc);
322         if (rc!=DS_OK)
323             return;
324     }
325 
326     /* DSOUND: Error: Invalid caps pointer */
327     rc=IDirectSoundBuffer_GetCaps(*dsbo,0);
328     ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have "
329        "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
330 
331     ZeroMemory(&dsbcaps, sizeof(dsbcaps));
332 
333     /* DSOUND: Error: Invalid caps pointer */
334     rc=IDirectSoundBuffer_GetCaps(*dsbo,&dsbcaps);
335     ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have "
336        "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
337 
338     dsbcaps.dwSize=sizeof(dsbcaps);
339     rc=IDirectSoundBuffer_GetCaps(*dsbo,&dsbcaps);
340     ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %08x\n", rc);
341     if (rc==DS_OK && winetest_debug > 1) {
342         trace("    Caps: flags=0x%08x size=%d\n",dsbcaps.dwFlags,
343               dsbcaps.dwBufferBytes);
344     }
345 
346     /* Query the format size. */
347     size=0;
348     rc=IDirectSoundBuffer_GetFormat(*dsbo,NULL,0,&size);
349     ok(rc==DS_OK && size!=0,"IDirectSoundBuffer_GetFormat() should have "
350        "returned the needed size: rc=%08x size=%d\n",rc,size);
351 
352     ok(size == sizeof(WAVEFORMATEX) || size == sizeof(WAVEFORMATEXTENSIBLE),
353        "Expected a correct structure size, got %d\n", size);
354 
355     if (size == sizeof(WAVEFORMATEX)) {
356         rc=IDirectSoundBuffer_GetFormat(*dsbo,&wfx,size,NULL);
357     }
358     else if (size == sizeof(WAVEFORMATEXTENSIBLE)) {
359         WAVEFORMATEXTENSIBLE wfxe;
360         rc=IDirectSoundBuffer_GetFormat(*dsbo,(WAVEFORMATEX*)&wfxe,size,NULL);
361         wfx = wfxe.Format;
362     }
363     ok(rc==DS_OK,
364         "IDirectSoundBuffer_GetFormat() failed: %08x\n", rc);
365     if (rc==DS_OK && winetest_debug > 1) {
366         trace("    Format: %s tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n",
367               is_primary ? "Primary" : "Secondary",
368               wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
369               wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
370     }
371 
372     /* DSOUND: Error: Invalid frequency buffer */
373     rc=IDirectSoundBuffer_GetFrequency(*dsbo,0);
374     ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetFrequency() should have "
375        "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
376 
377     /* DSOUND: Error: Primary buffers don't support CTRLFREQUENCY */
378     rc=IDirectSoundBuffer_GetFrequency(*dsbo,&freq);
379     ok((rc==DS_OK && !is_primary) || (rc==DSERR_CONTROLUNAVAIL&&is_primary) ||
380        (rc==DSERR_CONTROLUNAVAIL&&!(dsbcaps.dwFlags&DSBCAPS_CTRLFREQUENCY)),
381        "IDirectSoundBuffer_GetFrequency() failed: %08x\n",rc);
382     if (rc==DS_OK) {
383         DWORD f = set_frequency?frequency:wfx.nSamplesPerSec;
384         ok(freq==f,"The frequency returned by GetFrequency "
385            "%d does not match the format %d\n",freq,f);
386     }
387 
388     /* DSOUND: Error: Invalid status pointer */
389     rc=IDirectSoundBuffer_GetStatus(*dsbo,0);
390     ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetStatus() should have "
391        "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
392 
393     rc=IDirectSoundBuffer_GetStatus(*dsbo,&status);
394     ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %08x\n", rc);
395     ok(status==0,"status=0x%x instead of 0\n",status);
396 
397     if (is_primary) {
398         DSBCAPS new_dsbcaps;
399         /* We must call SetCooperativeLevel to be allowed to call SetFormat */
400         /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
401         rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
402         ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc);
403         if (rc!=DS_OK)
404             return;
405 
406         /* DSOUND: Error: Invalid format pointer */
407         rc=IDirectSoundBuffer_SetFormat(*dsbo,0);
408         ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_SetFormat() should have "
409            "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
410 
411         init_format(&wfx2,WAVE_FORMAT_PCM,11025,16,2);
412         rc=IDirectSoundBuffer_SetFormat(*dsbo,&wfx2);
413         ok(rc==DS_OK,"IDirectSoundBuffer_SetFormat(%s) failed: %08x\n",
414            format_string(&wfx2), rc);
415 
416         /* There is no guarantee that SetFormat will actually change the
417          * format to what we asked for. It depends on what the soundcard
418          * supports. So we must re-query the format.
419          */
420         rc=IDirectSoundBuffer_GetFormat(*dsbo,&wfx,sizeof(wfx),NULL);
421         ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %08x\n", rc);
422         if (rc==DS_OK &&
423             (wfx.wFormatTag!=wfx2.wFormatTag ||
424              wfx.nSamplesPerSec!=wfx2.nSamplesPerSec ||
425              wfx.wBitsPerSample!=wfx2.wBitsPerSample ||
426              wfx.nChannels!=wfx2.nChannels)) {
427             trace("Requested format tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n",
428                   wfx2.wFormatTag,wfx2.nSamplesPerSec,wfx2.wBitsPerSample,
429                   wfx2.nChannels,wfx2.nAvgBytesPerSec,wfx2.nBlockAlign);
430             trace("Got tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n",
431                   wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
432                   wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
433         }
434 
435         ZeroMemory(&new_dsbcaps, sizeof(new_dsbcaps));
436         new_dsbcaps.dwSize = sizeof(new_dsbcaps);
437         rc=IDirectSoundBuffer_GetCaps(*dsbo,&new_dsbcaps);
438         ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %08x\n", rc);
439         if (rc==DS_OK && winetest_debug > 1) {
440             trace("    new Caps: flags=0x%08x size=%d\n",new_dsbcaps.dwFlags,
441                   new_dsbcaps.dwBufferBytes);
442         }
443 
444         /* Check for primary buffer size change */
445         ok(new_dsbcaps.dwBufferBytes == dsbcaps.dwBufferBytes,
446            "    buffer size changed after SetFormat() - "
447            "previous size was %u, current size is %u\n",
448            dsbcaps.dwBufferBytes, new_dsbcaps.dwBufferBytes);
449         dsbcaps.dwBufferBytes = new_dsbcaps.dwBufferBytes;
450 
451         /* Check for primary buffer flags change */
452         ok(new_dsbcaps.dwFlags == dsbcaps.dwFlags,
453            "    flags changed after SetFormat() - "
454            "previous flags were %08x, current flags are %08x\n",
455            dsbcaps.dwFlags, new_dsbcaps.dwFlags);
456 
457         /* Set the CooperativeLevel back to normal */
458         /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
459         rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
460         ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n",rc);
461     }
462 
463     if (play) {
464         play_state_t state;
465         DS3DLISTENER listener_param;
466         LPDIRECTSOUND3DBUFFER buffer=NULL;
467         DS3DBUFFER buffer_param;
468         DWORD start_time,now;
469         LPVOID buffer1;
470         DWORD length1;
471 
472         if (winetest_interactive) {
473             if (set_frequency)
474                 trace("    Playing %g second 440Hz tone at %dx%dx%d with a "
475                       "frequency of %d (%dHz)\n", duration,
476                       wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nChannels,
477                       frequency, (440 * frequency) / wfx.nSamplesPerSec);
478             else
479                 trace("    Playing %g second 440Hz tone at %dx%dx%d\n", duration,
480                       wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nChannels);
481         }
482 
483         if (is_primary) {
484             /* We must call SetCooperativeLevel to be allowed to call Lock */
485             /* DSOUND: Setting DirectSound cooperative level to
486              * DSSCL_WRITEPRIMARY */
487             rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),
488                                                 DSSCL_WRITEPRIMARY);
489             ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_WRITEPRIMARY) "
490                "failed: %08x\n",rc);
491             if (rc!=DS_OK)
492                 return;
493         }
494         if (buffer3d) {
495             LPDIRECTSOUNDBUFFER temp_buffer;
496 
497             rc=IDirectSoundBuffer_QueryInterface(*dsbo,&IID_IDirectSound3DBuffer,
498                                                  (LPVOID *)&buffer);
499             ok(rc==DS_OK,"IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc);
500             if (rc!=DS_OK)
501                 return;
502 
503             /* check the COM interface */
504             rc=IDirectSoundBuffer_QueryInterface(*dsbo, &IID_IDirectSoundBuffer,
505                                                  (LPVOID *)&temp_buffer);
506             ok(rc==DS_OK && temp_buffer!=NULL,
507                "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc);
508             ok(temp_buffer==*dsbo,"COM interface broken: %p != %p\n",
509                temp_buffer,*dsbo);
510             ref=IDirectSoundBuffer_Release(temp_buffer);
511             ok(ref==1,"IDirectSoundBuffer_Release() has %d references, "
512                "should have 1\n",ref);
513 
514             temp_buffer=NULL;
515             rc=IDirectSound3DBuffer_QueryInterface(*dsbo,
516                                                    &IID_IDirectSoundBuffer,
517                                                    (LPVOID *)&temp_buffer);
518             ok(rc==DS_OK && temp_buffer!=NULL,
519                "IDirectSound3DBuffer_QueryInterface() failed: %08x\n", rc);
520             ok(temp_buffer==*dsbo,"COM interface broken: %p != %p\n",
521                temp_buffer,*dsbo);
522             ref=IDirectSoundBuffer_Release(temp_buffer);
523             ok(ref==1,"IDirectSoundBuffer_Release() has %d references, "
524                "should have 1\n",ref);
525 
526             ref=IDirectSoundBuffer_Release(*dsbo);
527             ok(ref==0,"IDirectSoundBuffer_Release() has %d references, "
528                "should have 0\n",ref);
529 
530             rc=IDirectSound3DBuffer_QueryInterface(buffer,
531                                                    &IID_IDirectSoundBuffer,
532                                                    (LPVOID *)dsbo);
533             ok(rc==DS_OK && *dsbo!=NULL,"IDirectSound3DBuffer_QueryInterface() "
534                "failed: %08x\n",rc);
535 
536             /* DSOUND: Error: Invalid buffer */
537             rc=IDirectSound3DBuffer_GetAllParameters(buffer,0);
538             ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() "
539                "failed: %08x\n",rc);
540 
541             ZeroMemory(&buffer_param, sizeof(buffer_param));
542 
543             /* DSOUND: Error: Invalid buffer */
544             rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param);
545             ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() "
546                "failed: %08x\n",rc);
547 
548             buffer_param.dwSize=sizeof(buffer_param);
549             rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param);
550             ok(rc==DS_OK,"IDirectSound3DBuffer_GetAllParameters() failed: %08x\n", rc);
551         }
552         if (set_volume) {
553             if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) {
554                 LONG val;
555                 rc=IDirectSoundBuffer_GetVolume(*dsbo,&val);
556                 ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %08x\n", rc);
557 
558                 rc=IDirectSoundBuffer_SetVolume(*dsbo,volume);
559                 ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume() failed: %08x\n", rc);
560             } else {
561                 /* DSOUND: Error: Buffer does not have CTRLVOLUME */
562                 rc=IDirectSoundBuffer_GetVolume(*dsbo,&volume);
563                 ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetVolume() "
564                    "should have returned DSERR_CONTROLUNAVAIL, returned: %08x\n", rc);
565             }
566         }
567 
568         if (set_pan) {
569             if (dsbcaps.dwFlags & DSBCAPS_CTRLPAN) {
570                 LONG val;
571                 rc=IDirectSoundBuffer_GetPan(*dsbo,&val);
572                 ok(rc==DS_OK,"IDirectSoundBuffer_GetPan() failed: %08x\n", rc);
573 
574                 rc=IDirectSoundBuffer_SetPan(*dsbo,pan);
575                 ok(rc==DS_OK,"IDirectSoundBuffer_SetPan() failed: %08x\n", rc);
576             } else {
577                 /* DSOUND: Error: Buffer does not have CTRLPAN */
578                 rc=IDirectSoundBuffer_GetPan(*dsbo,&pan);
579                 ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetPan() "
580                    "should have returned DSERR_CONTROLUNAVAIL, returned: %08x\n", rc);
581             }
582         }
583 
584         /* try an offset past the end of the buffer */
585         rc = IDirectSoundBuffer_Lock(*dsbo, dsbcaps.dwBufferBytes, 0, &buffer1,
586                                       &length1, NULL, NULL,
587                                       DSBLOCK_ENTIREBUFFER);
588         ok(rc==DSERR_INVALIDPARAM, "IDirectSoundBuffer_Lock() should have "
589            "returned DSERR_INVALIDPARAM, returned %08x\n", rc);
590 
591         /* try a size larger than the buffer */
592         rc = IDirectSoundBuffer_Lock(*dsbo, 0, dsbcaps.dwBufferBytes + 1,
593                                      &buffer1, &length1, NULL, NULL,
594                                      DSBLOCK_FROMWRITECURSOR);
595         ok(rc==DSERR_INVALIDPARAM, "IDirectSoundBuffer_Lock() should have "
596            "returned DSERR_INVALIDPARAM, returned %08x\n", rc);
597 
598         if (set_frequency)
599             state.wave=wave_generate_la(&wfx,(duration*frequency)/wfx.nSamplesPerSec,&state.wave_len);
600         else
601             state.wave=wave_generate_la(&wfx,duration,&state.wave_len);
602 
603         state.dsbo=*dsbo;
604         state.wfx=&wfx;
605         state.buffer_size=dsbcaps.dwBufferBytes;
606         state.played=state.written=state.offset=0;
607         buffer_refill(&state,state.buffer_size);
608 
609         rc=IDirectSoundBuffer_Play(*dsbo,0,0,DSBPLAY_LOOPING);
610         ok(rc==DS_OK,"IDirectSoundBuffer_Play() failed: %08x\n", rc);
611 
612         rc=IDirectSoundBuffer_GetStatus(*dsbo,&status);
613         ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %08x\n", rc);
614         ok(status==(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING),
615            "GetStatus: bad status: %x\n",status);
616 
617         if (listener) {
618             ZeroMemory(&listener_param,sizeof(listener_param));
619             listener_param.dwSize=sizeof(listener_param);
620             rc=IDirectSound3DListener_GetAllParameters(listener,
621                                                        &listener_param);
622             ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() "
623                "failed: %08x\n",rc);
624             if (move_listener) {
625                 listener_param.vPosition.x = -5.0f;
626                 listener_param.vVelocity.x = (float)(10.0/duration);
627             }
628             rc=IDirectSound3DListener_SetAllParameters(listener,
629                                                        &listener_param,
630                                                        DS3D_IMMEDIATE);
631             ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %08x\n", rc);
632         }
633         if (buffer3d) {
634             if (move_sound) {
635                 buffer_param.vPosition.x = 100.0f;
636                 buffer_param.vVelocity.x = (float)(-200.0/duration);
637             }
638             buffer_param.flMinDistance = 10;
639             rc=IDirectSound3DBuffer_SetAllParameters(buffer,&buffer_param,
640                                                      DS3D_IMMEDIATE);
641             ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %08x\n", rc);
642         }
643 
644         start_time=GetTickCount();
645         while (buffer_service(&state)) {
646             WaitForSingleObject(GetCurrentProcess(),TIME_SLICE);
647             now=GetTickCount();
648             if (listener && move_listener) {
649                 listener_param.vPosition.x = (float)(-5.0+10.0*(now-start_time)/1000/duration);
650                 if (winetest_debug>2)
651                     trace("listener position=%g\n",listener_param.vPosition.x);
652                 rc=IDirectSound3DListener_SetPosition(listener,
653                     listener_param.vPosition.x,listener_param.vPosition.y,
654                     listener_param.vPosition.z,DS3D_IMMEDIATE);
655                 ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %08x\n",rc);
656             }
657             if (buffer3d && move_sound) {
658                 buffer_param.vPosition.x = (float)(100-200.0*(now-start_time)/1000/duration);
659                 if (winetest_debug>2)
660                     trace("sound position=%g\n",buffer_param.vPosition.x);
661                 rc=IDirectSound3DBuffer_SetPosition(buffer,
662                     buffer_param.vPosition.x,buffer_param.vPosition.y,
663                     buffer_param.vPosition.z,DS3D_IMMEDIATE);
664                 ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %08x\n", rc);
665             }
666         }
667         /* Check the sound duration was within 10% of the expected value */
668         now=GetTickCount();
669         ok(fabs(1000*duration-now+start_time)<=100*duration,
670            "The sound played for %d ms instead of %g ms\n",
671            now-start_time,1000*duration);
672 
673         free(state.wave);
674         if (is_primary) {
675             /* Set the CooperativeLevel back to normal */
676             /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
677             rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
678             ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) "
679                "failed: %08x\n",rc);
680         }
681         if (buffer3d) {
682             ref=IDirectSound3DBuffer_Release(buffer);
683             ok(ref==0,"IDirectSound3DBuffer_Release() has %d references, "
684                "should have 0\n",ref);
685         }
686     }
687 }
688 
689 static HRESULT test_secondary(LPGUID lpGuid, int play,
690                               int has_3d, int has_3dbuffer,
691                               int has_listener, int has_duplicate,
692                               int move_listener, int move_sound)
693 {
694     HRESULT rc;
695     LPDIRECTSOUND dso=NULL;
696     LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL;
697     LPDIRECTSOUND3DLISTENER listener=NULL;
698     DSBUFFERDESC bufdesc;
699     WAVEFORMATEX wfx, wfx1;
700     int ref;
701 
702     /* Create the DirectSound object */
703     rc=pDirectSoundCreate(lpGuid,&dso,NULL);
704     ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %08x\n", rc);
705     if (rc!=DS_OK)
706         return rc;
707 
708     /* We must call SetCooperativeLevel before creating primary buffer */
709     /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
710     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
711     ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc);
712     if (rc!=DS_OK)
713         goto EXIT;
714 
715     ZeroMemory(&bufdesc, sizeof(bufdesc));
716     bufdesc.dwSize=sizeof(bufdesc);
717     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
718     if (has_3d)
719         bufdesc.dwFlags|=DSBCAPS_CTRL3D;
720     else
721         bufdesc.dwFlags|=(DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN);
722     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
723     ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL),
724        "IDirectSound_CreateSoundBuffer() failed to create a %sprimary buffer: %08x\n",has_3d?"3D ":"", rc);
725     if (rc==DSERR_CONTROLUNAVAIL)
726         trace("  No Primary\n");
727     else if (rc==DS_OK && primary!=NULL) {
728         rc=IDirectSoundBuffer_GetFormat(primary,&wfx1,sizeof(wfx1),NULL);
729         ok(rc==DS_OK,"IDirectSoundBuffer8_Getformat() failed: %08x\n", rc);
730         if (rc!=DS_OK)
731             goto EXIT1;
732 
733         if (has_listener) {
734             rc=IDirectSoundBuffer_QueryInterface(primary,
735                                                  &IID_IDirectSound3DListener,
736                                                  (void **)&listener);
737             ok(rc==DS_OK && listener!=NULL,
738                "IDirectSoundBuffer_QueryInterface() failed to get a 3D listener: %08x\n",rc);
739             ref=IDirectSoundBuffer_Release(primary);
740             ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
741                "should have 0\n",ref);
742             if (rc==DS_OK && listener!=NULL) {
743                 DS3DLISTENER listener_param;
744                 ZeroMemory(&listener_param,sizeof(listener_param));
745                 /* DSOUND: Error: Invalid buffer */
746                 rc=IDirectSound3DListener_GetAllParameters(listener,0);
747                 ok(rc==DSERR_INVALIDPARAM,
748                    "IDirectSound3dListener_GetAllParameters() should have "
749                    "returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
750 
751                 /* DSOUND: Error: Invalid buffer */
752                 rc=IDirectSound3DListener_GetAllParameters(listener,
753                                                            &listener_param);
754                 ok(rc==DSERR_INVALIDPARAM,
755                    "IDirectSound3dListener_GetAllParameters() should have "
756                    "returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
757 
758                 listener_param.dwSize=sizeof(listener_param);
759                 rc=IDirectSound3DListener_GetAllParameters(listener,
760                                                            &listener_param);
761                 ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() "
762                    "failed: %08x\n",rc);
763             } else {
764                 ok(listener==NULL, "IDirectSoundBuffer_QueryInterface() "
765                    "failed but returned a listener anyway\n");
766                 ok(rc!=DS_OK, "IDirectSoundBuffer_QueryInterface() succeeded "
767                    "but returned a NULL listener\n");
768                 if (listener) {
769                     ref=IDirectSound3DListener_Release(listener);
770                     ok(ref==0,"IDirectSound3dListener_Release() listener has "
771                        "%d references, should have 0\n",ref);
772                 }
773                 goto EXIT2;
774             }
775         }
776 
777         init_format(&wfx,WAVE_FORMAT_PCM,22050,16,2);
778         secondary=NULL;
779         ZeroMemory(&bufdesc, sizeof(bufdesc));
780         bufdesc.dwSize=sizeof(bufdesc);
781         bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
782         if (has_3d)
783             bufdesc.dwFlags|=DSBCAPS_CTRL3D;
784         else
785             bufdesc.dwFlags|=
786                 (DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN);
787         bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000,
788                                     wfx.nBlockAlign);
789         bufdesc.lpwfxFormat=&wfx;
790         if (winetest_interactive) {
791             trace("  Testing a %s%ssecondary buffer %s%s%s%sat %dx%dx%d "
792                   "with a primary buffer at %dx%dx%d\n",
793                   has_3dbuffer?"3D ":"",
794                   has_duplicate?"duplicated ":"",
795                   listener!=NULL||move_sound?"with ":"",
796                   move_listener?"moving ":"",
797                   listener!=NULL?"listener ":"",
798                   listener&&move_sound?"and moving sound ":move_sound?
799                   "moving sound ":"",
800                   wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,
801                   wfx1.nSamplesPerSec,wfx1.wBitsPerSample,wfx1.nChannels);
802         }
803         rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
804         ok(rc==DS_OK && secondary!=NULL,"IDirectSound_CreateSoundBuffer() "
805            "failed to create a %s%ssecondary buffer %s%s%s%sat %dx%dx%d (%s): %08x\n",
806            has_3dbuffer?"3D ":"", has_duplicate?"duplicated ":"",
807            listener!=NULL||move_sound?"with ":"", move_listener?"moving ":"",
808            listener!=NULL?"listener ":"",
809            listener&&move_sound?"and moving sound ":move_sound?
810            "moving sound ":"",
811            wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,
812            getDSBCAPS(bufdesc.dwFlags),rc);
813         if (rc==DS_OK && secondary!=NULL) {
814             if (!has_3d) {
815                 LONG refvol,vol,refpan,pan;
816 
817                 /* Check the initial secondary buffer's volume and pan */
818                 rc=IDirectSoundBuffer_GetVolume(secondary,&vol);
819                 ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(secondary) failed: %08x\n",rc);
820                 ok(vol==0,"wrong volume for a new secondary buffer: %d\n",vol);
821                 rc=IDirectSoundBuffer_GetPan(secondary,&pan);
822                 ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(secondary) failed: %08x\n",rc);
823                 ok(pan==0,"wrong pan for a new secondary buffer: %d\n",pan);
824 
825                 /* Check that changing the secondary buffer's volume and pan
826                  * does not impact the primary buffer's volume and pan
827                  */
828                 rc=IDirectSoundBuffer_GetVolume(primary,&refvol);
829                 ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: %08x\n",rc);
830                 rc=IDirectSoundBuffer_GetPan(primary,&refpan);
831                 ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %08x\n", rc);
832 
833                 rc=IDirectSoundBuffer_SetVolume(secondary,-1000);
834                 ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc);
835                 rc=