277 lines
7.0 KiB
C
277 lines
7.0 KiB
C
|
#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);
|
||
|
}
|
||
|
|