dsound.c

来自「Wine-20031016」· C语言 代码 · 共 1,079 行 · 第 1/3 页

C
1,079
字号
/* * Unit tests for dsound functions * * Copyright (c) 2002 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 <stdlib.h>#include "wine/test.h"#include "windef.h"#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))/* 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.14159265358979323846static 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;}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",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",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",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",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",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->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) {	    state->last_pos=(state->offset<play_pos)?play_pos:0;	    if (winetest_debug > 1)		trace("last sound byte at %ld\n",		      (state->written % state->buffer_size));	}    } else {	if (state->last_pos!=0 && play_pos<state->last_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",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) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?