fceux/attic/sexyal/drivers/dsound.c

277 lines
7.0 KiB
C
Raw Normal View History

#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#undef WINNT
#define NONAMELESSUNION
#define DIRECTSOUND_VERSION 0x0300
#include <dsound.h>
#include "../sexyal.h"
typedef struct
{
LPDIRECTSOUND ppDS; /* DirectSound interface object. */
LPDIRECTSOUNDBUFFER ppbuf; /* Primary buffer. */
LPDIRECTSOUNDBUFFER ppbufsec; /* Secondary buffer. */
LPDIRECTSOUNDBUFFER ppbufw; /* Buffer to do writes to. */
WAVEFORMATEX wf; /* Format of the primary and secondary buffers. */
long DSBufferSize; /* The size of the buffer that we can write to, in bytes. */
long BufHowMuch; /* How many bytes we should try to buffer. */
DWORD ToWritePos; /* Position which the next write to the buffer
should write to.
*/
} DSFobby;
static void CheckStatus(DSFobby *tmp)
{
DWORD status=0;
IDirectSoundBuffer_GetStatus(tmp->ppbufw, &status);
if(status&DSBSTATUS_BUFFERLOST)
IDirectSoundBuffer_Restore(tmp->ppbufw);
if(!(status&DSBSTATUS_PLAYING))
{
tmp->ToWritePos=0;
IDirectSoundBuffer_SetCurrentPosition(tmp->ppbufsec,0);
IDirectSoundBuffer_SetFormat(tmp->ppbufw,&tmp->wf);
IDirectSoundBuffer_Play(tmp->ppbufw,0,0,DSBPLAY_LOOPING);
}
}
SexyAL_device *SexyALI_DSound_Open(uint64_t id, SexyAL_format *format, SexyAL_buffering *buffering)
{
SexyAL_device *dev;
DSFobby *fobby;
DSBUFFERDESC DSBufferDesc;
DSCAPS dscaps;
DSBCAPS dsbcaps;
dev=malloc(sizeof(SexyAL_device));
fobby=malloc(sizeof(DSFobby));
memset(fobby,0,sizeof(DSFobby));
memset(&fobby->wf,0,sizeof(WAVEFORMATEX));
fobby->wf.wFormatTag = WAVE_FORMAT_PCM;
fobby->wf.nChannels = format->channels;
fobby->wf.nSamplesPerSec = format->rate;
if(DirectSoundCreate(0,&fobby->ppDS,0) != DS_OK)
{
free(dev);
free(fobby);
return(0);
}
{
//HWND hWnd = GetForegroundWindow(); // Ugly.
//if(!hWnd)
//{ hWnd=GetDesktopWindow(); exit(1); }
HWND hWnd;
hWnd=GetDesktopWindow();
IDirectSound_SetCooperativeLevel(fobby->ppDS,hWnd,DSSCL_PRIORITY);
}
memset(&dscaps,0x00,sizeof(dscaps));
dscaps.dwSize=sizeof(dscaps);
IDirectSound_GetCaps(fobby->ppDS,&dscaps);
IDirectSound_Compact(fobby->ppDS);
/* Create primary buffer */
memset(&DSBufferDesc,0x00,sizeof(DSBUFFERDESC));
DSBufferDesc.dwSize=sizeof(DSBufferDesc);
DSBufferDesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
if(IDirectSound_CreateSoundBuffer(fobby->ppDS,&DSBufferDesc,&fobby->ppbuf,0) != DS_OK)
{
IDirectSound_Release(fobby->ppDS);
free(dev);
free(fobby);
return(0);
}
/* Set primary buffer format. */
if(format->sampformat == SEXYAL_FMT_PCMU8)
fobby->wf.wBitsPerSample=8;
else // if(format->sampformat == SEXYAL_FMT_PCMS16)
{
fobby->wf.wBitsPerSample=16;
format->sampformat=SEXYAL_FMT_PCMS16;
}
fobby->wf.nBlockAlign=fobby->wf.wBitsPerSample>>3;
fobby->wf.nAvgBytesPerSec=fobby->wf.nSamplesPerSec*fobby->wf.nBlockAlign;
if(IDirectSoundBuffer_SetFormat(fobby->ppbuf,&fobby->wf) != DS_OK)
{
IDirectSound_Release(fobby->ppbuf);
IDirectSound_Release(fobby->ppDS);
free(dev);
free(fobby);
return(0);
}
/* Create secondary sound buffer */
IDirectSoundBuffer_GetFormat(fobby->ppbuf,&fobby->wf,sizeof(WAVEFORMATEX),0);
memset(&DSBufferDesc,0x00,sizeof(DSBUFFERDESC));
DSBufferDesc.dwSize=sizeof(DSBufferDesc);
DSBufferDesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
DSBufferDesc.dwFlags|=DSBCAPS_GLOBALFOCUS;
DSBufferDesc.dwBufferBytes=65536;
DSBufferDesc.lpwfxFormat=&fobby->wf;
if(IDirectSound_CreateSoundBuffer(fobby->ppDS, &DSBufferDesc, &fobby->ppbufsec, 0) != DS_OK)
{
IDirectSound_Release(fobby->ppbuf);
IDirectSound_Release(fobby->ppDS);
free(dev);
free(fobby);
return(0);
}
fobby->DSBufferSize=65536;
IDirectSoundBuffer_SetCurrentPosition(fobby->ppbufsec,0);
fobby->ppbufw=fobby->ppbufsec;
memcpy(&dev->format,format,sizeof(SexyAL_format));
if(!buffering->ms)
buffering->ms=53;
buffering->totalsize=(int64_t)format->rate*buffering->ms/1000;
fobby->BufHowMuch=buffering->totalsize* format->channels * (format->sampformat>>4);
//printf("%d\n",fobby->BufHowMuch);
//fflush(stdout);
dev->private=fobby;
timeBeginPeriod(1);
return(dev);
}
uint32_t SexyALI_DSound_RawCanWrite(SexyAL_device *device)
{
DSFobby *tmp=device->private;
DWORD CurWritePos,CurPlayPos=0;
CheckStatus(tmp);
CurWritePos=0;
if(IDirectSoundBuffer_GetCurrentPosition(tmp->ppbufw,&CurPlayPos,&CurWritePos)==DS_OK)
{
//FCEU_DispMessage("%d",CurWritePos-CurPlayPos);
}
CurWritePos=(CurPlayPos+tmp->BufHowMuch)%tmp->DSBufferSize;
/* If the current write pos is >= half the buffer size less than the to write pos,
assume DirectSound has wrapped around.
*/
if(((int32_t)tmp->ToWritePos-(int32_t)CurWritePos) >= (tmp->DSBufferSize/2))
{
CurWritePos+=tmp->DSBufferSize;
//printf("Fixit: %d,%d,%d\n",tmp->ToWritePos,CurWritePos,CurWritePos-tmp->DSBufferSize);
}
if(tmp->ToWritePos<CurWritePos)
{
int32_t howmuch=(int32_t)CurWritePos-(int32_t)tmp->ToWritePos;
if(howmuch > tmp->BufHowMuch) /* Oopsie. Severe buffer overflow... */
{
tmp->ToWritePos=CurWritePos%tmp->DSBufferSize;
//IDirectSoundBuffer_Stop(tmp->ppbufsec);
//IDirectSoundBuffer_SetCurrentPosition(tmp->ppbufsec,tmp->ToWritePos);
//puts("Oops");
//fflush(stdout);
//return(0);
}
return(CurWritePos-tmp->ToWritePos);
}
else
return(0);
}
int SexyALI_DSound_RawWrite(SexyAL_device *device, void *data, uint32_t len)
{
DSFobby *tmp=device->private;
// uint32_t cw;
//printf("Pre: %d\n",SexyALI_DSound_RawCanWrite(device));
//fflush(stdout);
CheckStatus(tmp);
/* In this block, we write as much data as we can, then we write
the rest of it in >=1ms chunks.
*/
while(len)
{
VOID *LockPtr[2]={0,0};
DWORD LockLen[2]={0,0};
int32_t curlen;
while(!(curlen=SexyALI_DSound_RawCanWrite(device)))
{
Sleep(1);
}
if(curlen>len) curlen=len;
if(DS_OK == IDirectSoundBuffer_Lock(tmp->ppbufw,tmp->ToWritePos,curlen,&LockPtr[0],&LockLen[0],&LockPtr[1],&LockLen[1],0))
{
}
if(LockPtr[1] != 0 && LockPtr[1] != LockPtr[0])
{
memcpy(LockPtr[0],data,LockLen[0]);
memcpy(LockPtr[1],data+LockLen[0],len-LockLen[0]);
}
else if(LockPtr[0])
{
memcpy(LockPtr[0],data,curlen);
}
IDirectSoundBuffer_Unlock(tmp->ppbufw,LockPtr[0],LockLen[0],LockPtr[1],LockLen[1]);
tmp->ToWritePos=(tmp->ToWritePos+curlen)%tmp->DSBufferSize;
len-=curlen;
(uint8_t *) data+=curlen;
if(len)
Sleep(1);
} // end while(len) loop
return(1);
}
int SexyALI_DSound_Close(SexyAL_device *device)
{
if(device)
{
if(device->private)
{
DSFobby *tmp=device->private;
if(tmp->ppbufsec)
{
IDirectSoundBuffer_Stop(tmp->ppbufsec);
IDirectSoundBuffer_Release(tmp->ppbufsec);
}
if(tmp->ppbuf)
{
IDirectSoundBuffer_Stop(tmp->ppbuf);
IDirectSoundBuffer_Release(tmp->ppbuf);
}
if(tmp->ppDS)
{
IDirectSound_Release(tmp->ppDS);
}
free(device->private);
}
free(device);
timeEndPeriod(1);
return(1);
}
return(0);
}