diff --git a/dlls/dsound/tests/.cvsignore b/dlls/dsound/tests/.cvsignore index 5e912917c1c..a02054a5c55 100644 --- a/dlls/dsound/tests/.cvsignore +++ b/dlls/dsound/tests/.cvsignore @@ -1,5 +1,6 @@ Makefile capture.ok +ds3d.ok dsound.ok propset.ok testlist.c diff --git a/dlls/dsound/tests/Makefile.in b/dlls/dsound/tests/Makefile.in index 3ef6372d7ad..c097e51d478 100644 --- a/dlls/dsound/tests/Makefile.in +++ b/dlls/dsound/tests/Makefile.in @@ -8,6 +8,7 @@ EXTRALIBS = -ldxguid -luuid -ldxerr9 CTESTS = \ capture.c \ + ds3d.c \ dsound.c \ propset.c diff --git a/dlls/dsound/tests/capture.c b/dlls/dsound/tests/capture.c index 39178a00077..ff44fc48b7d 100644 --- a/dlls/dsound/tests/capture.c +++ b/dlls/dsound/tests/capture.c @@ -34,48 +34,10 @@ #include "mmreg.h" #include "dxerr9.h" -static const unsigned int formats[][3]={ - { 8000, 8, 1}, - { 8000, 8, 2}, - { 8000, 16, 1}, - { 8000, 16, 2}, - {11025, 8, 1}, - {11025, 8, 2}, - {11025, 16, 1}, - {11025, 16, 2}, - {22050, 8, 1}, - {22050, 8, 2}, - {22050, 16, 1}, - {22050, 16, 2}, - {44100, 8, 1}, - {44100, 8, 2}, - {44100, 16, 1}, - {44100, 16, 2}, - {48000, 8, 1}, - {48000, 8, 2}, - {48000, 16, 1}, - {48000, 16, 2}, - {96000, 8, 1}, - {96000, 8, 2}, - {96000, 16, 1}, - {96000, 16, 2} -}; -#define NB_FORMATS (sizeof(formats)/sizeof(*formats)) +#include "dsound_test.h" #define NOTIFICATIONS 5 -static void init_format(WAVEFORMATEX* wfx, int format, int rate, int depth, int channels) -{ - wfx->wFormatTag=format; - wfx->nChannels=channels; - wfx->wBitsPerSample=depth; - wfx->nSamplesPerSec=rate; - wfx->nBlockAlign=wfx->nChannels*wfx->wBitsPerSample/8; - if (wfx->nBlockAlign==0) /* align compressed formats to byte boundry */ - wfx->nBlockAlign=1; - wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nChannels*wfx->wBitsPerSample/8; - wfx->cbSize=0; -} static char * format_string(WAVEFORMATEX* wfx) { diff --git a/dlls/dsound/tests/ds3d.c b/dlls/dsound/tests/ds3d.c new file mode 100644 index 00000000000..ebe5ff93154 --- /dev/null +++ b/dlls/dsound/tests/ds3d.c @@ -0,0 +1,948 @@ +/* + * Tests the panning and 3D functions of DirectSound + * + * Part of this test involves playing test tones. But this only makes + * sense if someone is going to carefully listen to it, and would only + * bother everyone else. + * So this is only done if the test is being run in interactive mode. + * + * Copyright (c) 2002-2004 Francois Gouget + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define NONAMELESSSTRUCT +#define NONAMELESSUNION +#include + +#include +#include + +#include "wine/test.h" +#include "windef.h" +#include "wingdi.h" +#include "dsound.h" + +#include "dsound_test.h" + + +#define PI 3.14159265358979323846 +char* wave_generate_la(WAVEFORMATEX* wfx, double duration, DWORD* size) +{ + int i; + int nb_samples; + char* buf; + char* b; + + nb_samples=(int)(duration*wfx->nSamplesPerSec); + *size=nb_samples*wfx->nBlockAlign; + b=buf=malloc(*size); + for (i=0;inSamplesPerSec); + if (wfx->wBitsPerSample==8) { + unsigned char sample=(unsigned char)((double)127.5*(y+1.0)); + *b++=sample; + if (wfx->nChannels==2) + *b++=sample; + } else { + signed short sample=(signed short)((double)32767.5*y-0.5); + b[0]=sample & 0xff; + b[1]=sample >> 8; + b+=2; + if (wfx->nChannels==2) { + b[0]=sample & 0xff; + b[1]=sample >> 8; + b+=2; + } + } + } + return buf; +} + +HWND get_hwnd() +{ + HWND hwnd=GetForegroundWindow(); + if (!hwnd) + hwnd=GetDesktopWindow(); + return hwnd; +} + +void init_format(WAVEFORMATEX* wfx, int format, int rate, int depth, int channels) +{ + wfx->wFormatTag=format; + wfx->nChannels=channels; + wfx->wBitsPerSample=depth; + wfx->nSamplesPerSec=rate; + wfx->nBlockAlign=wfx->nChannels*wfx->wBitsPerSample/8; + /* FIXME: Shouldn't this test be if (format!=WAVE_FORMAT_PCM) */ + if (wfx->nBlockAlign==0) + { + /* align compressed formats to byte boundary */ + wfx->nBlockAlign=1; + } + wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nBlockAlign; + wfx->cbSize=0; +} + +typedef struct { + char* wave; + DWORD wave_len; + + LPDIRECTSOUNDBUFFER dsbo; + LPWAVEFORMATEX wfx; + DWORD buffer_size; + DWORD written; + DWORD offset; + + DWORD last_pos; +} play_state_t; + +static int buffer_refill(play_state_t* state, DWORD size) +{ + LPVOID ptr1,ptr2; + DWORD len1,len2; + HRESULT rc; + + if (size>state->wave_len-state->written) + size=state->wave_len-state->written; + + rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, + &ptr1,&len1,&ptr2,&len2,0); + ok(rc==DS_OK,"Lock: 0x%lx\n",rc); + if (rc!=DS_OK) + return -1; + + memcpy(ptr1,state->wave+state->written,len1); + state->written+=len1; + if (ptr2!=NULL) { + memcpy(ptr2,state->wave+state->written,len2); + state->written+=len2; + } + state->offset=state->written % state->buffer_size; + rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2); + ok(rc==DS_OK,"Unlock: 0x%lx\n",rc); + if (rc!=DS_OK) + return -1; + return size; +} + +static int buffer_silence(play_state_t* state, DWORD size) +{ + LPVOID ptr1,ptr2; + DWORD len1,len2; + HRESULT rc; + BYTE s; + + rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, + &ptr1,&len1,&ptr2,&len2,0); + ok(rc==DS_OK,"Lock: 0x%lx\n",rc); + if (rc!=DS_OK) + return -1; + + s=(state->wfx->wBitsPerSample==8?0x80:0); + memset(ptr1,s,len1); + if (ptr2!=NULL) { + memset(ptr2,s,len2); + } + state->offset=(state->offset+size) % state->buffer_size; + rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2); + ok(rc==DS_OK,"Unlock: 0x%lx\n",rc); + if (rc!=DS_OK) + return -1; + return size; +} + +static int buffer_service(play_state_t* state) +{ + DWORD play_pos,write_pos,buf_free; + HRESULT rc; + + rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,&write_pos); + ok(rc==DS_OK,"GetCurrentPosition: %lx\n",rc); + if (rc!=DS_OK) { + goto STOP; + } + + /* Refill the buffer */ + if (state->offset<=play_pos) { + buf_free=play_pos-state->offset; + } else { + buf_free=state->buffer_size-state->offset+play_pos; + } + if (winetest_debug > 1) + trace("buf pos=%ld free=%ld written=%ld / %ld\n", + play_pos,buf_free,state->written,state->wave_len); + if (buf_free==0) + return 1; + + if (state->writtenwave_len) { + int w=buffer_refill(state,buf_free); + if (w==-1) + goto STOP; + buf_free-=w; + if (state->written==state->wave_len) { + state->last_pos=(state->offset 1) + trace("last sound byte at %ld\n", + (state->written % state->buffer_size)); + } + } else { + if (state->last_pos!=0 && play_poslast_pos) { + /* We wrapped around the end of the buffer */ + state->last_pos=0; + } + if (state->last_pos==0 && + play_pos>(state->written % state->buffer_size)) { + /* Now everything has been played */ + goto STOP; + } + } + + if (buf_free>0) { + /* Fill with silence */ + if (winetest_debug > 1) + trace("writing %ld bytes of silence\n",buf_free); + if (buffer_silence(state,buf_free)==-1) + goto STOP; + } + return 1; + +STOP: + if (winetest_debug > 1) + trace("stopping playback\n"); + rc=IDirectSoundBuffer_Stop(state->dsbo); + ok(rc==DS_OK,"Stop failed: rc=%ld\n",rc); + return 0; +} + +void test_buffer(LPDIRECTSOUND dso, LPDIRECTSOUNDBUFFER dsbo, + BOOL is_primary, BOOL set_volume, LONG volume, + BOOL set_pan, LONG pan, BOOL play, double duration, + BOOL buffer3d, LPDIRECTSOUND3DLISTENER listener, + BOOL move_listener, BOOL move_sound) +{ + HRESULT rc; + DSBCAPS dsbcaps; + WAVEFORMATEX wfx,wfx2; + DWORD size,status,freq; + int ref; + + /* DSOUND: Error: Invalid caps pointer */ + rc=IDirectSoundBuffer_GetCaps(dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc); + + ZeroMemory(&dsbcaps, sizeof(dsbcaps)); + + /* DSOUND: Error: Invalid caps pointer */ + rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps); + ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc); + + dsbcaps.dwSize=sizeof(dsbcaps); + rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps); + ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc); + if (rc==DS_OK) { + trace(" Caps: flags=0x%08lx size=%ld\n",dsbcaps.dwFlags, + dsbcaps.dwBufferBytes); + } + + /* Query the format size. Note that it may not match sizeof(wfx) */ + size=0; + rc=IDirectSoundBuffer_GetFormat(dsbo,NULL,0,&size); + ok(rc==DS_OK && size!=0, + "GetFormat should have returned the needed size: rc=0x%lx size=%ld\n", + rc,size); + + rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL); + ok(rc==DS_OK,"GetFormat failed: 0x%lx\n",rc); + if (rc==DS_OK && is_primary) { + trace("Primary buffer default format: tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", + wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, + wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); + } + + /* DSOUND: Error: Invalid frequency buffer */ + rc=IDirectSoundBuffer_GetFrequency(dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"GetFrequency should have failed: 0x%lx\n",rc); + + /* DSOUND: Error: Primary buffers don't support CTRLFREQUENCY */ + rc=IDirectSoundBuffer_GetFrequency(dsbo,&freq); + ok((rc==DS_OK && !is_primary) || (rc==DSERR_CONTROLUNAVAIL&&is_primary) || + (rc==DSERR_CONTROLUNAVAIL&&!(dsbcaps.dwFlags&DSBCAPS_CTRLFREQUENCY)), + "GetFrequency failed: 0x%lx\n",rc); + if (rc==DS_OK) { + ok(freq==wfx.nSamplesPerSec, + "The frequency returned by GetFrequency %ld does not match the format %ld\n", + freq,wfx.nSamplesPerSec); + } + + /* DSOUND: Error: Invalid status pointer */ + rc=IDirectSoundBuffer_GetStatus(dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"GetStatus should have failed: 0x%lx\n",rc); + + rc=IDirectSoundBuffer_GetStatus(dsbo,&status); + ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc); + ok(status==0,"status=0x%lx instead of 0\n",status); + + if (is_primary) { + /* We must call SetCooperativeLevel to be allowed to call SetFormat */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc); + if (rc!=DS_OK) + return; + + /* DSOUND: Error: Invalid format pointer */ + rc=IDirectSoundBuffer_SetFormat(dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"SetFormat should have failed: 0x%lx\n",rc); + + init_format(&wfx2,WAVE_FORMAT_PCM,11025,16,2); + rc=IDirectSoundBuffer_SetFormat(dsbo,&wfx2); + ok(rc==DS_OK,"SetFormat failed: 0x%lx\n",rc); + + /* There is no garantee that SetFormat will actually change the + * format to what we asked for. It depends on what the soundcard + * supports. So we must re-query the format. + */ + rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL); + ok(rc==DS_OK,"GetFormat failed: 0x%lx\n",rc); + if (rc==DS_OK && + (wfx.wFormatTag!=wfx2.wFormatTag || + wfx.nSamplesPerSec!=wfx2.nSamplesPerSec || + wfx.wBitsPerSample!=wfx2.wBitsPerSample || + wfx.nChannels!=wfx2.nChannels)) { + trace("Requested format tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", + wfx2.wFormatTag,wfx2.nSamplesPerSec,wfx2.wBitsPerSample, + wfx2.nChannels,wfx2.nAvgBytesPerSec,wfx2.nBlockAlign); + trace("Got tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", + wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, + wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); + } + + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc); + } + + if (play) { + play_state_t state; + DS3DLISTENER listener_param; + LPDIRECTSOUND3DBUFFER buffer=NULL; + DS3DBUFFER buffer_param; + + trace(" Playing %g second 440Hz tone at %ldx%dx%d\n", duration, + wfx.nSamplesPerSec, wfx.wBitsPerSample,wfx.nChannels); + + if (is_primary) { + /* We must call SetCooperativeLevel to be allowed to call Lock */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_WRITEPRIMARY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_WRITEPRIMARY); + ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc); + if (rc!=DS_OK) + return; + } + if (buffer3d) { + LPDIRECTSOUNDBUFFER temp_buffer; + + rc=IDirectSoundBuffer_QueryInterface(dsbo,&IID_IDirectSound3DBuffer,(LPVOID *)&buffer); + ok(rc==DS_OK,"QueryInterface failed: 0x%lx\n",rc); + if (rc!=DS_OK) + return; + + /* check the COM interface */ + rc=IDirectSoundBuffer_QueryInterface(dsbo, &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL,"QueryInterface failed: 0x%lx\n",rc); + ok(temp_buffer==dsbo,"COM interface broken: 0x%08lx != 0x%08lx\n",(DWORD)temp_buffer,(DWORD)dsbo); + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release has %d references, should have 1\n",ref); + + temp_buffer=NULL; + rc=IDirectSound3DBuffer_QueryInterface(dsbo, &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL,"IDirectSound3DBuffer_QueryInterface failed: 0x%lx\n",rc); + ok(temp_buffer==dsbo,"COM interface broken: 0x%08lx != 0x%08lx\n",(DWORD)temp_buffer,(DWORD)dsbo); + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release has %d references, should have 1\n",ref); + +#if 0 + /* FIXME: this works on windows */ + ref=IDirectSoundBuffer_Release(dsbo); + ok(ref==0,"IDirectSoundBuffer_Release has %d references, should have 0\n",ref); + + rc=IDirectSound3DBuffer_QueryInterface(buffer, &IID_IDirectSoundBuffer,(LPVOID *)&dsbo); + ok(rc==DS_OK && dsbo!=NULL,"IDirectSound3DBuffer_QueryInterface failed: 0x%lx\n",rc); +#endif + + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DBuffer_GetAllParameters(buffer,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters failed: 0x%lx\n",rc); + + ZeroMemory(&buffer_param, sizeof(buffer_param)); + + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters failed: 0x%lx\n",rc); + + buffer_param.dwSize=sizeof(buffer_param); + rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param); + ok(rc==DS_OK,"IDirectSound3DBuffer_GetAllParameters failed: 0x%lx\n",rc); +} + if (set_volume) { + if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) { + LONG val; + rc=IDirectSoundBuffer_GetVolume(dsbo,&val); + ok(rc==DS_OK,"GetVolume failed: 0x%lx\n",rc); + + rc=IDirectSoundBuffer_SetVolume(dsbo,volume); + ok(rc==DS_OK,"SetVolume failed: 0x%lx\n",rc); + } else { + /* DSOUND: Error: Buffer does not have CTRLVOLUME */ + rc=IDirectSoundBuffer_GetVolume(dsbo,&volume); + ok(rc==DSERR_CONTROLUNAVAIL,"GetVolume should have failed: 0x%lx\n",rc); + } + } + + if (set_pan) { + if (dsbcaps.dwFlags & DSBCAPS_CTRLPAN) { + LONG val; + rc=IDirectSoundBuffer_GetPan(dsbo,&val); + ok(rc==DS_OK,"GetPan failed: 0x%lx\n",rc); + + rc=IDirectSoundBuffer_SetPan(dsbo,pan); + ok(rc==DS_OK,"SetPan failed: 0x%lx\n",rc); + + rc=IDirectSoundBuffer_GetPan(dsbo,&val); + ok(val==pan,"volume=%ld instead of %ld\n",val,pan); + } else { + /* DSOUND: Error: Buffer does not have CTRLPAN */ + rc=IDirectSoundBuffer_GetPan(dsbo,&pan); + ok(rc==DSERR_CONTROLUNAVAIL,"GetPan should have failed: 0x%lx\n",rc); + } + } + + state.wave=wave_generate_la(&wfx,duration,&state.wave_len); + + state.dsbo=dsbo; + state.wfx=&wfx; + state.buffer_size=dsbcaps.dwBufferBytes; + state.written=state.offset=0; + buffer_refill(&state,state.buffer_size); + + rc=IDirectSoundBuffer_Play(dsbo,0,0,DSBPLAY_LOOPING); + ok(rc==DS_OK,"Play: 0x%lx\n",rc); + + rc=IDirectSoundBuffer_GetStatus(dsbo,&status); + ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc); + ok(status==(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING), + "GetStatus: bad status: %lx\n",status); + + if (listener) { + ZeroMemory(&listener_param,sizeof(listener_param)); + listener_param.dwSize=sizeof(listener_param); + rc=IDirectSound3DListener_GetAllParameters(listener,&listener_param); + ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters failed 0x%lx\n",rc); + if (move_listener) + listener_param.vPosition.x = -5.0; + else + listener_param.vPosition.x = 0.0; + listener_param.vPosition.y = 0.0; + listener_param.vPosition.z = 0.0; + rc=IDirectSound3DListener_SetPosition(listener,listener_param.vPosition.x,listener_param.vPosition.y,listener_param.vPosition.z,DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dListener_SetPosition failed 0x%lx\n",rc); + } + if (buffer3d) { + if (move_sound) + buffer_param.vPosition.x = 5.0; + else + buffer_param.vPosition.x = 0.0; + buffer_param.vPosition.y = 0.0; + buffer_param.vPosition.z = 0.0; + rc=IDirectSound3DBuffer_SetPosition(buffer,buffer_param.vPosition.x,buffer_param.vPosition.y,buffer_param.vPosition.z,DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition failed 0x%lx\n",rc); + } + + while (buffer_service(&state)) { + WaitForSingleObject(GetCurrentProcess(),TIME_SLICE/2); + if (listener && move_listener) { + listener_param.vPosition.x += 0.5; + rc=IDirectSound3DListener_SetPosition(listener,listener_param.vPosition.x,listener_param.vPosition.y,listener_param.vPosition.z,DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dListener_SetPosition failed 0x%lx\n",rc); + } + if (buffer3d && move_sound) { + buffer_param.vPosition.x -= 0.5; + rc=IDirectSound3DBuffer_SetPosition(buffer,buffer_param.vPosition.x,buffer_param.vPosition.y,buffer_param.vPosition.z,DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition failed 0x%lx\n",rc); + } + } + + free(state.wave); + if (is_primary) { + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc); + } + if (buffer3d) { + ref=IDirectSound3DBuffer_Release(buffer); + ok(ref==0,"IDirectSound3DBuffer_Release has %d references, should have 0\n",ref); + } + } +} + +static HRESULT test_secondary(LPGUID lpGuid, int play, + int has_3d, int has_3dbuffer, + int has_listener, int has_duplicate, + int move_listener, int move_sound) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; + LPDIRECTSOUND3DLISTENER listener=NULL; + DSBUFFERDESC bufdesc; + WAVEFORMATEX wfx; + int ref; + + /* Create the DirectSound object */ + rc=DirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc); + if (rc!=DS_OK) + return rc; + + /* We must call SetCooperativeLevel before creating primary buffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc); + if (rc!=DS_OK) + goto EXIT; + + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; + if (has_3d) + bufdesc.dwFlags|=DSBCAPS_CTRL3D; + else + bufdesc.dwFlags|=(DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN); + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"CreateSoundBuffer failed to create a %sprimary buffer 0x%lx\n",has_3d?"3D ":"", rc); + + if (rc==DS_OK && primary!=NULL) { + if (has_listener) { + rc=IDirectSoundBuffer_QueryInterface(primary,&IID_IDirectSound3DListener,(void **)&listener); + ok(rc==DS_OK && listener!=NULL,"IDirectSoundBuffer_QueryInterface failed to get a 3D listener 0x%lx\n",rc); + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref); + if (rc==DS_OK && listener!=NULL) { + DS3DLISTENER listener_param; + ZeroMemory(&listener_param,sizeof(listener_param)); + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DListener_GetAllParameters(listener,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound3dListener_GetAllParameters failed 0x%lx\n",rc); + + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DListener_GetAllParameters(listener,&listener_param); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound3dListener_GetAllParameters failed 0x%lx\n",rc); + + listener_param.dwSize=sizeof(listener_param); + rc=IDirectSound3DListener_GetAllParameters(listener,&listener_param); + ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters failed 0x%lx\n",rc); + } + else + goto EXIT; + } + + init_format(&wfx,WAVE_FORMAT_PCM,22050,16,2); + secondary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2; + if (has_3d) + bufdesc.dwFlags|=DSBCAPS_CTRL3D; + else + bufdesc.dwFlags|=(DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN); + bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec*BUFFER_LEN/1000; + bufdesc.lpwfxFormat=&wfx; + trace(" Testing a %s%ssecondary buffer %s%s%s%sat %ldx%dx%d\n", + has_3dbuffer?"3D ":"", + has_duplicate?"duplicated ":"", + listener!=NULL||move_sound?"with ":"", + move_listener?"moving ":"", + listener!=NULL?"listener ":"", + listener&&move_sound?"and moving sound ":move_sound?"moving sound ":"", + wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels); + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK && secondary!=NULL,"CreateSoundBuffer failed to create a 3D secondary buffer 0x%lx\n",rc); + if (rc==DS_OK && secondary!=NULL) { + if (has_duplicate) { + LPDIRECTSOUNDBUFFER duplicated=NULL; + + /* DSOUND: Error: Invalid source buffer */ + rc=IDirectSound_DuplicateSoundBuffer(dso,0,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound_DuplicateSoundBuffer should have failed 0x%lx\n",rc); + + /* DSOUND: Error: Invalid dest buffer */ + rc=IDirectSound_DuplicateSoundBuffer(dso,secondary,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound_DuplicateSoundBuffer should have failed 0x%lx\n",rc); + + /* DSOUND: Error: Invalid source buffer */ + rc=IDirectSound_DuplicateSoundBuffer(dso,0,&duplicated); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound_DuplicateSoundBuffer should have failed 0x%lx\n",rc); + + duplicated=NULL; + rc=IDirectSound_DuplicateSoundBuffer(dso,secondary,&duplicated); + ok(rc==DS_OK && duplicated!=NULL,"IDirectSound_DuplicateSoundBuffer failed to duplicate a secondary buffer 0x%lx\n",rc); + + if (rc==DS_OK && duplicated!=NULL) { + ref=IDirectSoundBuffer_Release(secondary); + ok(ref==0,"IDirectSoundBuffer_Release secondary has %d references, should have 0\n",ref); + secondary=duplicated; + } + } + + if (rc==DS_OK && secondary!=NULL) { + double duration; + duration=(move_listener || move_sound?4.0:1.0); + test_buffer(dso,secondary,0,FALSE,0,FALSE,0,winetest_interactive,duration,has_3dbuffer,listener,move_listener,move_sound); + ref=IDirectSoundBuffer_Release(secondary); + ok(ref==0,"IDirectSoundBuffer_Release %s has %d references, should have 0\n",has_duplicate?"duplicated":"secondary",ref); + } + } + } + if (has_listener) { + ref=IDirectSound3DListener_Release(listener); + ok(ref==0,"IDirectSound3dListener_Release listener has %d references, should have 0\n",ref); + } else { + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref); + } + + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc); + +EXIT: + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_dsound(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + DWORD speaker_config, new_speaker_config; + int ref; + + /* The basic DirectSound tests are performed in the playback test */ + + /* Create the DirectSound object */ + rc=DirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc); + if (rc!=DS_OK) + return rc; + + rc=IDirectSound_GetSpeakerConfig(dso,0); + ok(rc==DSERR_INVALIDPARAM,"GetSpeakerConfig should have failed: 0x%lx\n",rc); + + rc=IDirectSound_GetSpeakerConfig(dso,&speaker_config); + ok(rc==DS_OK,"GetSpeakerConfig failed: 0x%lx\n",rc); + if (rc==DS_OK) { + trace(" DirectSound SpeakerConfig: 0x%08lx\n", speaker_config); + } + + speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO,DSSPEAKER_GEOMETRY_WIDE); + rc=IDirectSound_SetSpeakerConfig(dso,speaker_config); + ok(rc==DS_OK,"SetSpeakerConfig failed: 0x%lx\n",rc); + if (rc==DS_OK) { + rc=IDirectSound_GetSpeakerConfig(dso,&new_speaker_config); + ok(rc==DS_OK,"GetSpeakerConfig failed: 0x%lx\n",rc); + if (rc==DS_OK) + ok(speaker_config==new_speaker_config,"SetSpeakerConfig failed to set speaker config: expected 0x%08lx, got 0x%08lx\n", + speaker_config,new_speaker_config); + } + + /* Release the DirectSound object */ + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return DS_OK; +} + +static HRESULT test_primary(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + int ref, i; + + /* Create the DirectSound object */ + rc=DirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* Testing the primary buffer */ + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"CreateSoundBuffer failed to create a primary buffer: 0x%lx\n",rc); + if (rc==DS_OK && primary!=NULL) { + test_buffer(dso,primary,1,TRUE,0,TRUE,0,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,NULL,0,0); + if (winetest_interactive) { + LONG volume,pan; + + volume = DSBVOLUME_MAX; + for (i = 0; i < 6; i++) { + test_buffer(dso,primary,1,TRUE,volume,TRUE,0,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,NULL,0,0); + volume -= ((DSBVOLUME_MAX-DSBVOLUME_MIN) / 40); + } + + pan = DSBPAN_LEFT; + for (i = 0; i < 7; i++) { + test_buffer(dso,primary,1,TRUE,0,TRUE,pan,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0); + pan += ((DSBPAN_RIGHT-DSBPAN_LEFT) / 6); + } + } + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref); + } + + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc); + +EXIT: + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_primary_3d(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + int ref; + + /* Create the DirectSound object */ + rc=DirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc); + if (rc!=DS_OK) + goto EXIT; + + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"CreateSoundBuffer failed to create a primary buffer: 0x%lx\n",rc); + if (rc==DS_OK && primary!=NULL) { + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref); + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"CreateSoundBuffer failed to create a 3D primary buffer: 0x%lx\n",rc); + if (rc==DS_OK && primary!=NULL) { + test_buffer(dso,primary,1,FALSE,0,FALSE,0,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0); + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref); + } + } + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc); + +EXIT: + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_primary_3d_with_listener(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + int ref; + + /* Create the DirectSound object */ + rc=DirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc); + if (rc!=DS_OK) + goto EXIT; + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"CreateSoundBuffer failed to create a 3D primary buffer 0x%lx\n",rc); + if (rc==DS_OK && primary!=NULL) { + LPDIRECTSOUND3DLISTENER listener=NULL; + rc=IDirectSoundBuffer_QueryInterface(primary,&IID_IDirectSound3DListener,(void **)&listener); + ok(rc==DS_OK && listener!=NULL,"IDirectSoundBuffer_QueryInterface failed to get a 3D listener 0x%lx\n",rc); + if (rc==DS_OK && listener!=NULL) { + LPDIRECTSOUNDBUFFER temp_buffer=NULL; + + /* Checking the COM interface */ + rc=IDirectSoundBuffer_QueryInterface(primary, &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL,"IDirectSoundBuffer_QueryInterface failed: 0x%lx\n",rc); + ok(temp_buffer==primary,"COM interface broken: 0x%08lx != 0x%08lx\n",(DWORD)temp_buffer,(DWORD)primary); + if (rc==DS_OK && temp_buffer!=NULL) { + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release has %d references, should have 1\n",ref); + + temp_buffer=NULL; + rc=IDirectSound3DListener_QueryInterface(listener, &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL,"IDirectSoundBuffer_QueryInterface failed: 0x%lx\n",rc); + ok(temp_buffer==primary,"COM interface broken: 0x%08lx != 0x%08lx\n",(DWORD)temp_buffer,(DWORD)primary); + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release has %d references, should have 1\n",ref); + + /* Testing the buffer */ + test_buffer(dso,primary,1,FALSE,0,FALSE,0,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,listener,0,0); + } + + /* Testing the reference counting */ + ref=IDirectSound3DListener_Release(listener); + ok(ref==0,"IDirectSound3DListener_Release listener has %d references, should have 0\n",ref); + } + + /* Testing the reference counting */ + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref); + } + +EXIT: + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release has %d references, should have 0\n",ref); + if (ref!=0) +return DSERR_GENERIC; + + return rc; +} + +static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, + LPCSTR lpcstrModule, LPVOID lpContext) +{ + trace("*** Testing %s - %s\n",lpcstrDescription,lpcstrModule); + test_dsound(lpGuid); + + trace(" Testing the primary buffer\n"); + test_primary(lpGuid); + + trace(" Testing 3D primary buffer\n"); + test_primary_3d(lpGuid); + + trace(" Testing 3D primary buffer with listener\n"); + test_primary_3d_with_listener(lpGuid); + + /* Testing secondary buffers */ + test_secondary(lpGuid,winetest_interactive,0,0,0,0,0,0); + test_secondary(lpGuid,winetest_interactive,0,0,0,1,0,0); + + /* Testing 3D secondary buffers */ + test_secondary(lpGuid,winetest_interactive,1,0,0,0,0,0); + test_secondary(lpGuid,winetest_interactive,1,1,0,0,0,0); + test_secondary(lpGuid,winetest_interactive,1,1,0,1,0,0); + test_secondary(lpGuid,winetest_interactive,1,0,1,0,0,0); + test_secondary(lpGuid,winetest_interactive,1,0,1,1,0,0); + test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,0); + test_secondary(lpGuid,winetest_interactive,1,1,1,1,0,0); + test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,0); + test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,1); + test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,1); + + return 1; +} + +static void ds3d_tests() +{ + HRESULT rc; + rc=DirectSoundEnumerateA(&dsenum_callback,NULL); + ok(rc==DS_OK,"DirectSoundEnumerate failed: %ld\n",rc); +} + +START_TEST(ds3d) +{ + ds3d_tests(); +} diff --git a/dlls/dsound/tests/dsound.c b/dlls/dsound/tests/dsound.c index e7009e212fe..ea311a33bf9 100644 --- a/dlls/dsound/tests/dsound.c +++ b/dlls/dsound/tests/dsound.c @@ -1,7 +1,14 @@ /* - * Unit tests for dsound functions + * Tests basic sound playback in DirectSound. + * In particular we test each standard Windows sound format to make sure + * we handle the sound card/driver quirks correctly. * - * Copyright (c) 2002 Francois Gouget + * Part of this test involves playing test tones. But this only makes + * sense if someone is going to carefully listen to it, and would only + * bother everyone else. + * So this is only done if the test is being run in interactive mode. + * + * Copyright (c) 2002-2004 Francois Gouget * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -30,666 +37,14 @@ #include "wingdi.h" #include "dsound.h" -static const unsigned int formats[][3]={ - { 8000, 8, 1}, - { 8000, 8, 2}, - { 8000, 16, 1}, - { 8000, 16, 2}, - {11025, 8, 1}, - {11025, 8, 2}, - {11025, 16, 1}, - {11025, 16, 2}, - {22050, 8, 1}, - {22050, 8, 2}, - {22050, 16, 1}, - {22050, 16, 2}, - {44100, 8, 1}, - {44100, 8, 2}, - {44100, 16, 1}, - {44100, 16, 2}, - {48000, 8, 1}, - {48000, 8, 2}, - {48000, 16, 1}, - {48000, 16, 2}, - {96000, 8, 1}, - {96000, 8, 2}, - {96000, 16, 1}, - {96000, 16, 2} -}; -#define NB_FORMATS (sizeof(formats)/sizeof(*formats)) +#include "dsound_test.h" -/* The time slice determines how often we will service the buffer and the - * buffer will be four time slices long - */ -#define TIME_SLICE 100 -#define BUFFER_LEN (4*TIME_SLICE) -#define TONE_DURATION (6*TIME_SLICE) - -/* This test can play a test tone. But this only makes sense if someone - * is going to carefully listen to it, and would only bother everyone else. - * So this is only done if the test is being run in interactive mode. - */ - -#define PI 3.14159265358979323846 -static char* wave_generate_la(WAVEFORMATEX* wfx, double duration, DWORD* size) -{ - int i; - int nb_samples; - char* buf; - char* b; - - nb_samples=(int)(duration*wfx->nSamplesPerSec); - *size=nb_samples*wfx->nBlockAlign; - b=buf=malloc(*size); - for (i=0;inSamplesPerSec); - if (wfx->wBitsPerSample==8) { - unsigned char sample=(unsigned char)((double)127.5*(y+1.0)); - *b++=sample; - if (wfx->nChannels==2) - *b++=sample; - } else { - signed short sample=(signed short)((double)32767.5*y-0.5); - b[0]=sample & 0xff; - b[1]=sample >> 8; - b+=2; - if (wfx->nChannels==2) { - b[0]=sample & 0xff; - b[1]=sample >> 8; - b+=2; - } - } - } - return buf; -} - -static HWND get_hwnd() -{ - HWND hwnd=GetForegroundWindow(); - if (!hwnd) - hwnd=GetDesktopWindow(); - return hwnd; -} - -static void init_format(WAVEFORMATEX* wfx, int rate, int depth, int channels) -{ - wfx->wFormatTag=WAVE_FORMAT_PCM; - wfx->nChannels=channels; - wfx->wBitsPerSample=depth; - wfx->nSamplesPerSec=rate; - wfx->nBlockAlign=wfx->nChannels*wfx->wBitsPerSample/8; - wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nBlockAlign; - wfx->cbSize=0; -} - -typedef struct { - char* wave; - DWORD wave_len; - - LPDIRECTSOUNDBUFFER dsbo; - LPWAVEFORMATEX wfx; - DWORD buffer_size; - DWORD written; - DWORD offset; - - DWORD last_pos; -} play_state_t; - -static int buffer_refill(play_state_t* state, DWORD size) -{ - LPVOID ptr1,ptr2; - DWORD len1,len2; - HRESULT rc; - - if (size>state->wave_len-state->written) - size=state->wave_len-state->written; - - rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, - &ptr1,&len1,&ptr2,&len2,0); - ok(rc==DS_OK,"Lock: 0x%lx\n",rc); - if (rc!=DS_OK) - return -1; - - memcpy(ptr1,state->wave+state->written,len1); - state->written+=len1; - if (ptr2!=NULL) { - memcpy(ptr2,state->wave+state->written,len2); - state->written+=len2; - } - state->offset=state->written % state->buffer_size; - rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2); - ok(rc==DS_OK,"Unlock: 0x%lx\n",rc); - if (rc!=DS_OK) - return -1; - return size; -} - -static int buffer_silence(play_state_t* state, DWORD size) -{ - LPVOID ptr1,ptr2; - DWORD len1,len2; - HRESULT rc; - BYTE s; - - rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, - &ptr1,&len1,&ptr2,&len2,0); - ok(rc==DS_OK,"Lock: 0x%lx\n",rc); - if (rc!=DS_OK) - return -1; - - s=(state->wfx->wBitsPerSample==8?0x80:0); - memset(ptr1,s,len1); - if (ptr2!=NULL) { - memset(ptr2,s,len2); - } - state->offset=(state->offset+size) % state->buffer_size; - rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2); - ok(rc==DS_OK,"Unlock: 0x%lx\n",rc); - if (rc!=DS_OK) - return -1; - return size; -} - -static int buffer_service(play_state_t* state) -{ - DWORD play_pos,write_pos,buf_free; - HRESULT rc; - - rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,&write_pos); - ok(rc==DS_OK,"GetCurrentPosition: %lx\n",rc); - if (rc!=DS_OK) { - goto STOP; - } - - /* Refill the buffer */ - if (state->offset<=play_pos) { - buf_free=play_pos-state->offset; - } else { - buf_free=state->buffer_size-state->offset+play_pos; - } - if (winetest_debug > 1) - trace("buf pos=%ld free=%ld written=%ld / %ld\n", - play_pos,buf_free,state->written,state->wave_len); - if (buf_free==0) - return 1; - - if (state->writtenwave_len) { - int w=buffer_refill(state,buf_free); - if (w==-1) - goto STOP; - buf_free-=w; - if (state->written==state->wave_len) { - state->last_pos=(state->offset 1) - trace("last sound byte at %ld\n", - (state->written % state->buffer_size)); - } - } else { - if (state->last_pos!=0 && play_poslast_pos) { - /* We wrapped around the end of the buffer */ - state->last_pos=0; - } - if (state->last_pos==0 && - play_pos>(state->written % state->buffer_size)) { - /* Now everything has been played */ - goto STOP; - } - } - - if (buf_free>0) { - /* Fill with silence */ - if (winetest_debug > 1) - trace("writing %ld bytes of silence\n",buf_free); - if (buffer_silence(state,buf_free)==-1) - goto STOP; - } - return 1; - -STOP: - if (winetest_debug > 1) - trace("stopping playback\n"); - rc=IDirectSoundBuffer_Stop(state->dsbo); - ok(rc==DS_OK,"Stop failed: rc=%ld\n",rc); - return 0; -} - -static void test_buffer(LPDIRECTSOUND dso, LPDIRECTSOUNDBUFFER dsbo, - int is_primary, BOOL set_volume, LONG volume, - BOOL set_pan, LONG pan, int play, int buffer3d, - LPDIRECTSOUND3DLISTENER listener, - int move_listener, int move_sound) -{ - HRESULT rc; - DSBCAPS dsbcaps; - WAVEFORMATEX wfx,wfx2; - DWORD size,status,freq; - int ref; - - /* DSOUND: Error: Invalid caps pointer */ - rc=IDirectSoundBuffer_GetCaps(dsbo,0); - ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc); - - ZeroMemory(&dsbcaps, sizeof(dsbcaps)); - - /* DSOUND: Error: Invalid caps pointer */ - rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps); - ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc); - - dsbcaps.dwSize=sizeof(dsbcaps); - rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps); - ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc); - if (rc==DS_OK) { - trace(" Caps: flags=0x%08lx size=%ld\n",dsbcaps.dwFlags, - dsbcaps.dwBufferBytes); - } - - /* Query the format size. Note that it may not match sizeof(wfx) */ - size=0; - rc=IDirectSoundBuffer_GetFormat(dsbo,NULL,0,&size); - ok(rc==DS_OK && size!=0, - "GetFormat should have returned the needed size: rc=0x%lx size=%ld\n", - rc,size); - - rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL); - ok(rc==DS_OK,"GetFormat failed: 0x%lx\n",rc); - if (rc==DS_OK) { - trace(" tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", - wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, - wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); - } - - /* DSOUND: Error: Invalid frequency buffer */ - rc=IDirectSoundBuffer_GetFrequency(dsbo,0); - ok(rc==DSERR_INVALIDPARAM,"GetFrequency should have failed: 0x%lx\n",rc); - - /* DSOUND: Error: Primary buffers don't support CTRLFREQUENCY */ - rc=IDirectSoundBuffer_GetFrequency(dsbo,&freq); - ok((rc==DS_OK&&!is_primary) || (rc==DSERR_CONTROLUNAVAIL&&is_primary) || - (rc==DSERR_CONTROLUNAVAIL&&!(dsbcaps.dwFlags&DSBCAPS_CTRLFREQUENCY)), - "GetFrequency failed: 0x%lx\n",rc); - if (rc==DS_OK) { - ok(freq==wfx.nSamplesPerSec, - "The frequency returned by GetFrequency %ld does not match the format %ld\n", - freq,wfx.nSamplesPerSec); - } - - /* DSOUND: Error: Invalid status pointer */ - rc=IDirectSoundBuffer_GetStatus(dsbo,0); - ok(rc==DSERR_INVALIDPARAM,"GetStatus should have failed: 0x%lx\n",rc); - - rc=IDirectSoundBuffer_GetStatus(dsbo,&status); - ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc); - if (rc==DS_OK) { - trace(" status=0x%04lx\n",status); - } - - if (is_primary) { - /* We must call SetCooperativeLevel to be allowed to call SetFormat */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc); - if(rc!=DS_OK) - return; - - /* DSOUND: Error: Invalid format pointer */ - rc=IDirectSoundBuffer_SetFormat(dsbo,0); - ok(rc==DSERR_INVALIDPARAM,"SetFormat should have failed: 0x%lx\n",rc); - - init_format(&wfx2,11025,16,2); - rc=IDirectSoundBuffer_SetFormat(dsbo,&wfx2); - ok(rc==DS_OK,"SetFormat failed: 0x%lx\n",rc); - - /* There is no garantee that SetFormat will actually change the - * format to what we asked for. It depends on what the soundcard - * supports. So we must re-query the format. - */ - rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL); - ok(rc==DS_OK,"GetFormat failed: 0x%lx\n",rc); - if (rc==DS_OK) { - trace(" tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", - wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, - wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); - } - - /* Set the CooperativeLevel back to normal */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); - ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc); - } - - if (play) { - play_state_t state; - - LPDIRECTSOUND3DBUFFER buffer=NULL; - DS3DBUFFER buffer_param; - DS3DLISTENER listener_param; - trace(" Playing 440Hz LA at %ldx%dx%d\n", - wfx.nSamplesPerSec, wfx.wBitsPerSample,wfx.nChannels); - - if (is_primary) { - /* We must call SetCooperativeLevel to be allowed to call Lock */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_WRITEPRIMARY */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_WRITEPRIMARY); - ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc); - if (rc!=DS_OK) - return; - } - if (buffer3d) { - LPDIRECTSOUNDBUFFER temp_buffer; - - rc=IDirectSoundBuffer_QueryInterface(dsbo,&IID_IDirectSound3DBuffer,(LPVOID *)&buffer); - ok(rc==DS_OK,"QueryInterface failed: 0x%lx\n",rc); - if(rc!=DS_OK) - return; - - /* check the COM interface */ - rc=IDirectSoundBuffer_QueryInterface(dsbo, &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer); - ok(rc==DS_OK&&temp_buffer!=NULL,"QueryInterface failed: 0x%lx\n",rc); - ok(temp_buffer==dsbo,"COM interface broken: 0x%08lx != 0x%08lx\n",(DWORD)temp_buffer,(DWORD)dsbo); - ref=IDirectSoundBuffer_Release(temp_buffer); - ok(ref==1,"IDirectSoundBuffer_Release has %d references, should have 1\n",ref); - - temp_buffer=NULL; - rc=IDirectSound3DBuffer_QueryInterface(dsbo, &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer); - ok(rc==DS_OK&&temp_buffer!=NULL,"IDirectSound3DBuffer_QueryInterface failed: 0x%lx\n",rc); - ok(temp_buffer==dsbo,"COM interface broken: 0x%08lx != 0x%08lx\n",(DWORD)temp_buffer,(DWORD)dsbo); - ref=IDirectSoundBuffer_Release(temp_buffer); - ok(ref==1,"IDirectSoundBuffer_Release has %d references, should have 1\n",ref); - -#if 0 /* FIXME: this works on windows */ - ref=IDirectSoundBuffer_Release(dsbo); - ok(ref==0,"IDirectSoundBuffer_Release has %d references, should have 0\n",ref); - - rc=IDirectSound3DBuffer_QueryInterface(buffer, &IID_IDirectSoundBuffer,(LPVOID *)&dsbo); - ok(rc==DS_OK&&dsbo!=NULL,"IDirectSound3DBuffer_QueryInterface failed: 0x%lx\n",rc); -#endif - - /* DSOUND: Error: Invalid buffer */ - rc=IDirectSound3DBuffer_GetAllParameters(buffer,0); - ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters failed: 0x%lx\n",rc); - - ZeroMemory(&buffer_param, sizeof(buffer_param)); - - /* DSOUND: Error: Invalid buffer */ - rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param); - ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters failed: 0x%lx\n",rc); - - buffer_param.dwSize=sizeof(buffer_param); - rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param); - ok(rc==DS_OK,"IDirectSound3DBuffer_GetAllParameters failed: 0x%lx\n",rc); - } - if (set_volume) { - rc=IDirectSoundBuffer_SetVolume(dsbo,volume); - ok(rc==DS_OK,"SetVolume failed: 0x%lx\n",rc); - - rc=IDirectSoundBuffer_GetVolume(dsbo,&volume); - trace(" volume=%ld\n",volume); - } else { - if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) { - rc=IDirectSoundBuffer_GetVolume(dsbo,&volume); - ok(rc==DS_OK,"GetVolume failed: 0x%lx\n",rc); - - rc=IDirectSoundBuffer_SetVolume(dsbo,-300); - ok(rc==DS_OK,"SetVolume failed: 0x%lx\n",rc); - - rc=IDirectSoundBuffer_GetVolume(dsbo,&volume); - trace(" volume=%ld\n",volume); - } else { - /* DSOUND: Error: Buffer does not have CTRLVOLUME */ - rc=IDirectSoundBuffer_GetVolume(dsbo,&volume); - ok(rc==DSERR_CONTROLUNAVAIL,"GetVolume should have failed: 0x%lx\n",rc); - } - } - - if (set_pan) { - rc=IDirectSoundBuffer_SetPan(dsbo,pan); - ok(rc==DS_OK,"SetPan failed: 0x%lx\n",rc); - - rc=IDirectSoundBuffer_GetPan(dsbo,&pan); - trace(" pan=%ld\n",pan); - } else { - if (dsbcaps.dwFlags & DSBCAPS_CTRLPAN) { - rc=IDirectSoundBuffer_GetPan(dsbo,&pan); - ok(rc==DS_OK,"GetPan failed: 0x%lx\n",rc); - - rc=IDirectSoundBuffer_SetPan(dsbo,0); - ok(rc==DS_OK,"SetPan failed: 0x%lx\n",rc); - - rc=IDirectSoundBuffer_GetPan(dsbo,&pan); - trace(" pan=%ld\n",pan); - } else { - /* DSOUND: Error: Buffer does not have CTRLPAN */ - rc=IDirectSoundBuffer_GetPan(dsbo,&pan); - ok(rc==DSERR_CONTROLUNAVAIL,"GetPan should have failed: 0x%lx\n",rc); - } - } - - state.wave=wave_generate_la(&wfx,((double)TONE_DURATION)/1000,&state.wave_len); - - state.dsbo=dsbo; - state.wfx=&wfx; - state.buffer_size=dsbcaps.dwBufferBytes; - state.written=state.offset=0; - buffer_refill(&state,state.buffer_size); - - rc=IDirectSoundBuffer_Play(dsbo,0,0,DSBPLAY_LOOPING); - ok(rc==DS_OK,"Play: 0x%lx\n",rc); - - rc=IDirectSoundBuffer_GetStatus(dsbo,&status); - ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc); - ok(status==(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING), - "GetStatus: bad status: %lx\n",status); - - if (listener) { - ZeroMemory(&listener_param,sizeof(listener_param)); - listener_param.dwSize=sizeof(listener_param); - rc=IDirectSound3DListener_GetAllParameters(listener,&listener_param); - ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters failed 0x%lx\n",rc); - if (move_listener) - listener_param.vPosition.x = -5.0; - else - listener_param.vPosition.x = 0.0; - listener_param.vPosition.y = 0.0; - listener_param.vPosition.z = 0.0; - rc=IDirectSound3DListener_SetPosition(listener,listener_param.vPosition.x,listener_param.vPosition.y,listener_param.vPosition.z,DS3D_IMMEDIATE); - ok(rc==DS_OK,"IDirectSound3dListener_SetPosition failed 0x%lx\n",rc); - } - if (buffer3d) { - if (move_sound) - buffer_param.vPosition.x = 5.0; - else - buffer_param.vPosition.x = 0.0; - buffer_param.vPosition.y = 0.0; - buffer_param.vPosition.z = 0.0; - rc=IDirectSound3DBuffer_SetPosition(buffer,buffer_param.vPosition.x,buffer_param.vPosition.y,buffer_param.vPosition.z,DS3D_IMMEDIATE); - ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition failed 0x%lx\n",rc); - } - - while (buffer_service(&state)) { - WaitForSingleObject(GetCurrentProcess(),TIME_SLICE/2); - if (listener&&move_listener) { - listener_param.vPosition.x += 0.5; - rc=IDirectSound3DListener_SetPosition(listener,listener_param.vPosition.x,listener_param.vPosition.y,listener_param.vPosition.z,DS3D_IMMEDIATE); - ok(rc==DS_OK,"IDirectSound3dListener_SetPosition failed 0x%lx\n",rc); - } - if (buffer3d&&move_sound) { - buffer_param.vPosition.x -= 0.5; - rc=IDirectSound3DBuffer_SetPosition(buffer,buffer_param.vPosition.x,buffer_param.vPosition.y,buffer_param.vPosition.z,DS3D_IMMEDIATE); - ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition failed 0x%lx\n",rc); - } - } - - if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) { - rc=IDirectSoundBuffer_SetVolume(dsbo,volume); - ok(rc==DS_OK,"SetVolume failed: 0x%lx\n",rc); - } - - free(state.wave); - if (is_primary) { - /* Set the CooperativeLevel back to normal */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); - ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc); - } - if (buffer3d) { - ref=IDirectSound3DBuffer_Release(buffer); - ok(ref==0,"IDirectSound3DBuffer_Release has %d references, should have 0\n",ref); - } - } -} - -static HRESULT test_secondary(LPGUID lpGuid, int play, - int has_3d, int has_3dbuffer, - int has_listener, int has_duplicate, - int move_listener, int move_sound) -{ - HRESULT rc; - LPDIRECTSOUND dso=NULL; - LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; - LPDIRECTSOUND3DLISTENER listener=NULL; - DSBUFFERDESC bufdesc; - DSCAPS dscaps; - WAVEFORMATEX wfx; - int f,ref; - - /* Create the DirectSound object */ - rc=DirectSoundCreate(lpGuid,&dso,NULL); - ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc); - if (rc!=DS_OK) - return rc; - - /* Get the device capabilities */ - ZeroMemory(&dscaps, sizeof(dscaps)); - dscaps.dwSize=sizeof(dscaps); - rc=IDirectSound_GetCaps(dso,&dscaps); - ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc); - if (rc!=DS_OK) - goto EXIT; - - /* We must call SetCooperativeLevel before creating primary buffer */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc); - if(rc!=DS_OK) - goto EXIT; - - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; - if (has_3d) - bufdesc.dwFlags|=DSBCAPS_CTRL3D; - else - bufdesc.dwFlags|=(DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN); - rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DS_OK&&primary!=NULL,"CreateSoundBuffer failed to create a %sprimary buffer 0x%lx\n",has_3d?"3D ":"", rc); - if (rc==DS_OK&&primary!=NULL) { - if (has_listener) { - rc=IDirectSoundBuffer_QueryInterface(primary,&IID_IDirectSound3DListener,(void **)&listener); - ok(rc==DS_OK&&listener!=NULL,"IDirectSoundBuffer_QueryInterface failed to get a 3D listener 0x%lx\n",rc); - ref=IDirectSoundBuffer_Release(primary); - ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref); - if(rc==DS_OK&&listener!=NULL) { - DS3DLISTENER listener_param; - ZeroMemory(&listener_param,sizeof(listener_param)); - /* DSOUND: Error: Invalid buffer */ - rc=IDirectSound3DListener_GetAllParameters(listener,0); - ok(rc==DSERR_INVALIDPARAM,"IDirectSound3dListener_GetAllParameters failed 0x%lx\n",rc); - - /* DSOUND: Error: Invalid buffer */ - rc=IDirectSound3DListener_GetAllParameters(listener,&listener_param); - ok(rc==DSERR_INVALIDPARAM,"IDirectSound3dListener_GetAllParameters failed 0x%lx\n",rc); - - listener_param.dwSize=sizeof(listener_param); - rc=IDirectSound3DListener_GetAllParameters(listener,&listener_param); - ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters failed 0x%lx\n",rc); - } else - goto EXIT; - } - - for (f=0;f