📄 ds3d.c
字号:
/*
* 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 <windows.h>
#include <math.h>
#include "wine/test.h"
#include "dsound.h"
#include "dxerr8.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;i<nb_samples;i++) {
double y=sin(440.0*2*PI*i/wfx->nSamplesPerSec);
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;
}
const char * getDSBCAPS(DWORD xmask) {
static struct {
DWORD mask;
const char *name;
} flags[] = {
#define FE(x) { x, #x },
FE(DSBCAPS_PRIMARYBUFFER)
FE(DSBCAPS_STATIC)
FE(DSBCAPS_LOCHARDWARE)
FE(DSBCAPS_LOCSOFTWARE)
FE(DSBCAPS_CTRL3D)
FE(DSBCAPS_CTRLFREQUENCY)
FE(DSBCAPS_CTRLPAN)
FE(DSBCAPS_CTRLVOLUME)
FE(DSBCAPS_CTRLPOSITIONNOTIFY)
FE(DSBCAPS_STICKYFOCUS)
FE(DSBCAPS_GLOBALFOCUS)
FE(DSBCAPS_GETCURRENTPOSITION2)
FE(DSBCAPS_MUTE3DATMAXDISTANCE)
#undef FE
};
static char buffer[512];
unsigned int i;
BOOL first = TRUE;
buffer[0] = 0;
for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++) {
if ((flags[i].mask & xmask) == flags[i].mask) {
if (first)
first = FALSE;
else
strcat(buffer, "|");
strcat(buffer, flags[i].name);
}
}
return buffer;
}
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 played;
DWORD offset;
} 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,"IDirectSoundBuffer_Lock() failed: %s\n",
DXGetErrorString8(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,"IDirectSoundBuffer_Unlock() failed: %s\n",
DXGetErrorString8(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,"IDirectSoundBuffer_Lock() failed: %s\n",
DXGetErrorString8(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,"IDirectSoundBuffer_Unlock() failed: %s\n",
DXGetErrorString8(rc));
if (rc!=DS_OK)
return -1;
return size;
}
static int buffer_service(play_state_t* state)
{
DWORD last_play_pos,play_pos,buf_free;
HRESULT rc;
rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,NULL);
ok(rc==DS_OK,"IDirectSoundBuffer_GetCurrentPosition() failed: %s\n",
DXGetErrorString8(rc));
if (rc!=DS_OK) {
goto STOP;
}
/* Update the amount played */
last_play_pos=state->played % state->buffer_size;
if (play_pos<last_play_pos)
state->played+=state->buffer_size-last_play_pos+play_pos;
else
state->played+=play_pos-last_play_pos;
if (winetest_debug > 1)
trace("buf size=%ld last_play_pos=%ld play_pos=%ld played=%ld / %ld\n",
state->buffer_size,last_play_pos,play_pos,state->played,
state->wave_len);
if (state->played>state->wave_len)
{
/* Everything has been played */
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("offset=%ld free=%ld written=%ld / %ld\n",
state->offset,buf_free,state->written,state->wave_len);
if (buf_free==0)
return 1;
if (state->written<state->wave_len)
{
int w=buffer_refill(state,buf_free);
if (w==-1)
goto STOP;
buf_free-=w;
if (state->written==state->wave_len && winetest_debug > 1)
trace("last sound byte at %ld\n",
(state->written % state->buffer_size));
}
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,"IDirectSoundBuffer_Stop() failed: %s\n",
DXGetErrorString8(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,
BOOL set_frequency, DWORD frequency)
{
HRESULT rc;
DSBCAPS dsbcaps;
WAVEFORMATEX wfx,wfx2;
DWORD size,status,freq;
int ref;
if (set_frequency) {
rc=IDirectSoundBuffer_SetFrequency(dsbo,frequency);
ok(rc==DS_OK||rc==DSERR_CONTROLUNAVAIL,
"IDirectSoundBuffer_SetFrequency() failed to set frequency "
"%s\n",DXGetErrorString8(rc));
if (rc!=DS_OK)
return;
}
/* DSOUND: Error: Invalid caps pointer */
rc=IDirectSoundBuffer_GetCaps(dsbo,0);
ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have "
"returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc));
ZeroMemory(&dsbcaps, sizeof(dsbcaps));
/* DSOUND: Error: Invalid caps pointer */
rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps);
ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have "
"returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -