-/* FCE Ultra - NES/Famicom Emulator\r
- *\r
- * Copyright notice for this file:\r
- * Copyright (C) 2002 Ben Parnell\r
- *\r
- * This program is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
- */\r
-\r
-FILE *soundlog=0;\r
-void WriteWaveData(int32 *Buffer, int Count);\r
-DWORD WINAPI DSThread(LPVOID lpParam);\r
-LPDIRECTSOUND ppDS=0;\r
-LPDIRECTSOUNDBUFFER ppbuf=0;\r
-LPDIRECTSOUNDBUFFER ppbufsec=0;\r
-LPDIRECTSOUNDBUFFER ppbufw;\r
-\r
-DSBUFFERDESC DSBufferDesc;\r
-WAVEFORMATEX wfa;\r
-WAVEFORMATEX wf;\r
-\r
-static int DSBufferSize=0;\r
-static int bittage;\r
-\r
-void TrashSound(void)\r
-{\r
- FCEUI_Sound(0);\r
- if(ppbufsec)\r
- {\r
- IDirectSoundBuffer_Stop(ppbufsec);\r
- IDirectSoundBuffer_Release(ppbufsec);\r
- ppbufsec=0;\r
- }\r
- if(ppbuf)\r
- {\r
- IDirectSoundBuffer_Stop(ppbuf);\r
- IDirectSoundBuffer_Release(ppbuf);\r
- ppbuf=0;\r
- }\r
- if(ppDS)\r
- {\r
- IDirectSound_Release(ppDS);\r
- ppDS=0;\r
- }\r
-}\r
-\r
-\r
- static VOID *feegle[2];\r
- static DWORD dook[2];\r
- static DWORD writepos=0,playpos=0,lplaypos=0;\r
-void CheckDStatus(void)\r
-{\r
- DWORD status;\r
- status=0;\r
- IDirectSoundBuffer_GetStatus(ppbufw, &status);\r
-\r
- if(status&DSBSTATUS_BUFFERLOST)\r
- {\r
- IDirectSoundBuffer_Restore(ppbufw);\r
- }\r
-\r
- if(!(status&DSBSTATUS_PLAYING))\r
- {\r
- lplaypos=0;\r
- writepos=((soundbufsize)<<bittage);\r
- IDirectSoundBuffer_SetFormat(ppbufw,&wf);\r
- IDirectSoundBuffer_Play(ppbufw,0,0,DSBPLAY_LOOPING);\r
- }\r
-}\r
-\r
-static int16 MBuffer[2048];\r
-void FCEUD_WriteSoundData(int32 *Buffer, int Count)\r
-{\r
- int P;\r
- int k=0;\r
-\r
- if(soundlog)\r
- WriteWaveData(Buffer, Count);\r
-\r
- if(!bittage)\r
- {\r
- for(P=0;P<Count;P++)\r
- *(((uint8*)MBuffer)+P)=((int8)(Buffer[P]>>8))^128;\r
- }\r
- else\r
- {\r
- for(P=0;P<Count;P++)\r
- MBuffer[P]=Buffer[P];\r
- }\r
- ilicpo:\r
- CheckDStatus();\r
- IDirectSoundBuffer_GetCurrentPosition(ppbufw,&playpos,0);\r
-\r
- if(writepos>=DSBufferSize) \r
- if(playpos<lplaypos)\r
- writepos-=DSBufferSize;\r
- lplaypos=playpos;\r
-\r
- /* If the write position is beyond the fill buffer, block. */\r
- if(writepos>=(playpos+(soundbufsize<<bittage)))\r
- //if(!(writepos<playpos+((soundbufsize)<<bittage)))\r
- {\r
- if(!NoWaiting)\r
- {\r
- if(soundsleep==1)\r
- {\r
- if(!k)\r
- {\r
- int stime; \r
-\r
- stime=writepos-(playpos+(soundbufsize<<bittage));\r
- stime*=1000;\r
- stime/=soundrate;\r
- stime>>=1;\r
- if(stime>=5)\r
- Sleep(stime);\r
- k=1;\r
- } \r
- }\r
- else if(soundsleep==2)\r
- {\r
- int stime; \r
- stime=writepos-(playpos+(soundbufsize<<bittage));\r
- stime*=1000;\r
- stime/=soundrate;\r
- stime>>=1;\r
- if(stime>=2)\r
- Sleep(stime);\r
- }\r
- }\r
- BlockingCheck();\r
- if(!soundo || NoWaiting) return;\r
- goto ilicpo;\r
- }\r
-\r
- if(netplaytype && netplayon)\r
- {\r
- if(writepos<=playpos+128)\r
- writepos=playpos+(soundbufsize<<bittage);\r
- }\r
-\r
- {\r
- feegle[0]=feegle[1]=0;\r
- dook[0]=dook[1]=0;\r
-\r
- \r
- ddrval=IDirectSoundBuffer_Lock(ppbufw,(writepos%DSBufferSize),Count<<bittage,&feegle[0],&dook[0],&feegle[1],&dook[1],0);\r
- if(ddrval!=DS_OK)\r
- goto nolock;\r
-\r
- if(feegle[1]!=0 && feegle[1]!=feegle[0])\r
- {\r
- if(soundflush)\r
- {\r
- memset(feegle[0],0x80,dook[0]);\r
- memset(feegle[1],0x80,dook[1]);\r
- }\r
- else\r
- {\r
- memcpy(feegle[0],(uint8 *)MBuffer,dook[0]);\r
- memcpy(feegle[1],((uint8 *)MBuffer)+dook[0],dook[1]);\r
- }\r
- }\r
- else\r
- {\r
- if(soundflush)\r
- memset(feegle[0],0x80,dook[0]);\r
- else\r
- memcpy(feegle[0],(uint8 *)MBuffer,dook[0]);\r
- }\r
-\r
- IDirectSoundBuffer_Unlock(ppbufw,feegle[0],dook[0],feegle[1],dook[1]);\r
- writepos+=Count<<bittage;\r
- }\r
- nolock:\r
- ///////// Ending\r
-}\r
-\r
-int InitSound()\r
-{\r
- DSCAPS dscaps;\r
- DSBCAPS dsbcaps;\r
-\r
- memset(&wf,0x00,sizeof(wf));\r
- wf.wFormatTag = WAVE_FORMAT_PCM;\r
- wf.nChannels = 1;\r
- wf.nSamplesPerSec = soundrate;\r
-\r
- ddrval=DirectSoundCreate(0,&ppDS,0);\r
- if (ddrval != DS_OK)\r
- {\r
- FCEUD_PrintError("DirectSound: Error creating DirectSound object.");\r
- return 0;\r
- }\r
-\r
- if(soundoptions&SO_SECONDARY)\r
- {\r
- trysecondary:\r
- ddrval=IDirectSound_SetCooperativeLevel(ppDS,hAppWnd,DSSCL_PRIORITY);\r
- if (ddrval != DS_OK)\r
- {\r
- FCEUD_PrintError("DirectSound: Error setting cooperative level to DDSCL_PRIORITY.");\r
- TrashSound();\r
- return 0;\r
- }\r
- }\r
- else\r
- {\r
- ddrval=IDirectSound_SetCooperativeLevel(ppDS,hAppWnd,DSSCL_WRITEPRIMARY);\r
- if (ddrval != DS_OK)\r
- {\r
- FCEUD_PrintError("DirectSound: Error setting cooperative level to DDSCL_WRITEPRIMARY. Forcing use of secondary sound buffer and trying again...");\r
- soundoptions|=SO_SECONDARY;\r
- goto trysecondary;\r
- }\r
- }\r
- memset(&dscaps,0x00,sizeof(dscaps));\r
- dscaps.dwSize=sizeof(dscaps);\r
- ddrval=IDirectSound_GetCaps(ppDS,&dscaps);\r
- if(ddrval!=DS_OK)\r
- {\r
- FCEUD_PrintError("DirectSound: Error getting capabilities.");\r
- return 0;\r
- }\r
-\r
- if(dscaps.dwFlags&DSCAPS_EMULDRIVER)\r
- FCEUD_PrintError("DirectSound: Sound device is being emulated through waveform-audio functions. Sound quality will most likely be awful. Try to update your sound device's sound drivers.");\r
-\r
- IDirectSound_Compact(ppDS);\r
-\r
- memset(&DSBufferDesc,0x00,sizeof(DSBUFFERDESC));\r
- DSBufferDesc.dwSize=sizeof(DSBufferDesc);\r
- if(soundoptions&SO_SECONDARY)\r
- DSBufferDesc.dwFlags=DSBCAPS_PRIMARYBUFFER;\r
- else\r
- DSBufferDesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_GETCURRENTPOSITION2;\r
-\r
- ddrval=IDirectSound_CreateSoundBuffer(ppDS,&DSBufferDesc,&ppbuf,0);\r
- if (ddrval != DS_OK)\r
- {\r
- FCEUD_PrintError("DirectSound: Error creating primary buffer.");\r
- TrashSound();\r
- return 0;\r
- } \r
-\r
- memset(&wfa,0x00,sizeof(wfa));\r
-\r
- if(soundoptions&SO_FORCE8BIT)\r
- bittage=0;\r
- else\r
- {\r
- bittage=1;\r
- if( (!(dscaps.dwFlags&DSCAPS_PRIMARY16BIT)) ||\r
- (!(dscaps.dwFlags&DSCAPS_SECONDARY16BIT) && (soundoptions&SO_SECONDARY)))\r
- {\r
- FCEUD_PrintError("DirectSound: 16-bit sound is not supported. Forcing 8-bit sound.");\r
- bittage=0;\r
- soundoptions|=SO_FORCE8BIT;\r
- }\r
- }\r
-\r
- wf.wBitsPerSample=8<<bittage;\r
- wf.nBlockAlign = bittage+1;\r
- wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;\r
- \r
- ddrval=IDirectSoundBuffer_SetFormat(ppbuf,&wf);\r
- if (ddrval != DS_OK)\r
- {\r
- FCEUD_PrintError("DirectSound: Error setting primary buffer format.");\r
- TrashSound();\r
- return 0;\r
- }\r
-\r
- IDirectSoundBuffer_GetFormat(ppbuf,&wfa,sizeof(wfa),0);\r
-\r
- if(soundoptions&SO_SECONDARY)\r
- {\r
- memset(&DSBufferDesc,0x00,sizeof(DSBUFFERDESC)); \r
- DSBufferDesc.dwSize=sizeof(DSBufferDesc);\r
- DSBufferDesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;\r
- if(soundoptions&SO_GFOCUS)\r
- DSBufferDesc.dwFlags|=DSBCAPS_GLOBALFOCUS;\r
- DSBufferDesc.dwBufferBytes=32768;\r
- DSBufferDesc.lpwfxFormat=&wfa; \r
- ddrval=IDirectSound_CreateSoundBuffer(ppDS, &DSBufferDesc, &ppbufsec, 0);\r
- if (ddrval != DS_OK)\r
- {\r
- FCEUD_PrintError("DirectSound: Error creating secondary buffer.");\r
- TrashSound();\r
- return 0;\r
- }\r
- }\r
-\r
- //sprintf(TempArray,"%d\n",wfa.nSamplesPerSec);\r
- //FCEUD_PrintError(TempArray);\r
-\r
- if(soundoptions&SO_SECONDARY)\r
- {\r
- DSBufferSize=32768;\r
- IDirectSoundBuffer_SetCurrentPosition(ppbufsec,0);\r
- ppbufw=ppbufsec;\r
- }\r
- else\r
- {\r
- memset(&dsbcaps,0,sizeof(dsbcaps));\r
- dsbcaps.dwSize=sizeof(dsbcaps);\r
- ddrval=IDirectSoundBuffer_GetCaps(ppbuf,&dsbcaps);\r
- if (ddrval != DS_OK)\r
- {\r
- FCEUD_PrintError("DirectSound: Error getting buffer capabilities.");\r
- TrashSound();\r
- return 0;\r
- }\r
-\r
- DSBufferSize=dsbcaps.dwBufferBytes;\r
-\r
- if(DSBufferSize<8192)\r
- {\r
- FCEUD_PrintError("DirectSound: Primary buffer size is too small!");\r
- TrashSound();\r
- return 0;\r
- }\r
- ppbufw=ppbuf;\r
- }\r
-\r
- soundbufsize=(soundbuftime*soundrate/1000);\r
- FCEUI_Sound(soundrate);\r
- return 1;\r
-}\r
-\r
-BOOL CALLBACK SoundConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
-{\r
- int x;\r
-\r
- switch(uMsg) {\r
- case WM_INITDIALOG:\r
- if(soundo)\r
- CheckDlgButton(hwndDlg,126,BST_CHECKED);\r
- if(soundoptions&SO_FORCE8BIT)\r
- CheckDlgButton(hwndDlg,122,BST_CHECKED);\r
- if(soundoptions&SO_SECONDARY)\r
- CheckDlgButton(hwndDlg,123,BST_CHECKED);\r
- if(soundoptions&SO_GFOCUS)\r
- CheckDlgButton(hwndDlg,124,BST_CHECKED);\r
- SetDlgItemInt(hwndDlg,200,soundrate,0);\r
-\r
- /* Volume Trackbar */\r
- SendDlgItemMessage(hwndDlg,500,TBM_SETRANGE,1,MAKELONG(0,200));\r
- SendDlgItemMessage(hwndDlg,500,TBM_SETTICFREQ,25,0);\r
- SendDlgItemMessage(hwndDlg,500,TBM_SETPOS,1,200-soundvolume);\r
-\r
- /* buffer size time trackbar */\r
- SendDlgItemMessage(hwndDlg,128,TBM_SETRANGE,1,MAKELONG(15,200));\r
- SendDlgItemMessage(hwndDlg,128,TBM_SETTICFREQ,1,0);\r
- SendDlgItemMessage(hwndDlg,128,TBM_SETPOS,1,soundbuftime);\r
-\r
- {\r
- char tbuf[8];\r
- sprintf(tbuf,"%d",soundbuftime);\r
- SetDlgItemText(hwndDlg,666,(LPTSTR)tbuf);\r
- }\r
- \r
- SendDlgItemMessage(hwndDlg,129,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Mean");\r
- SendDlgItemMessage(hwndDlg,129,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Nice");\r
- SendDlgItemMessage(hwndDlg,129,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Nicest");\r
- SendDlgItemMessage(hwndDlg,129,CB_SETCURSEL,soundsleep,(LPARAM)(LPSTR)0);\r
- break;\r
- case WM_HSCROLL:\r
- // This doesn't seem to work. Hmm...\r
- //if((HWND)lParam==(HWND)128)\r
- {\r
- char tbuf[8];\r
- soundbuftime=SendDlgItemMessage(hwndDlg,128,TBM_GETPOS,0,0);\r
- sprintf(tbuf,"%d",soundbuftime);\r
- SetDlgItemText(hwndDlg,666,(LPTSTR)tbuf);\r
- }\r
- break;\r
- case WM_CLOSE:\r
- case WM_QUIT: goto gornk;\r
- case WM_COMMAND:\r
- if(!(wParam>>16))\r
- switch(wParam&0xFFFF)\r
- {\r
- case 1:\r
- gornk:\r
- soundoptions=0;\r
- if(IsDlgButtonChecked(hwndDlg,122)==BST_CHECKED)\r
- soundoptions|=SO_FORCE8BIT;\r
- if(IsDlgButtonChecked(hwndDlg,123)==BST_CHECKED)\r
- soundoptions|=SO_SECONDARY;\r
- if(IsDlgButtonChecked(hwndDlg,124)==BST_CHECKED)\r
- soundoptions|=SO_GFOCUS;\r
- if(IsDlgButtonChecked(hwndDlg,126)==BST_CHECKED)\r
- soundo=1;\r
- else\r
- soundo=0;\r
- x=GetDlgItemInt(hwndDlg,200,0,0);\r
- if(x<8192 || x>65535)\r
- {\r
- FCEUD_PrintError("Sample rate is out of range(8192-65535).");\r
- break;\r
- }\r
- else\r
- soundrate=x;\r
-\r
- soundvolume=200-SendDlgItemMessage(hwndDlg,500,TBM_GETPOS,0,0);\r
- FCEUI_SetSoundVolume(soundvolume);\r
- soundsleep=SendDlgItemMessage(hwndDlg,129,CB_GETCURSEL,0,(LPARAM)(LPSTR)0);\r
- EndDialog(hwndDlg,0);\r
- break;\r
- }\r
- }\r
- return 0;\r
-}\r
-\r
-\r
-void ConfigSound(void)\r
-{\r
- int backo=soundo,sr=soundrate;\r
- int so=soundoptions;\r
-\r
- DialogBox(fceu_hInstance,"SOUNDCONFIG",hAppWnd,SoundConCallB);\r
-\r
- if(((backo?1:0)!=(soundo?1:0)))\r
- {\r
- if(!soundo)\r
- TrashSound();\r
- else\r
- soundo=InitSound();\r
- }\r
- else if(( soundoptions!=so || (sr!=soundrate)) && soundo)\r
- {\r
- TrashSound();\r
- soundo=InitSound();\r
- }\r
- soundbufsize=(soundbuftime*soundrate/1000);\r
-}\r
-\r
-\r
-void StopSound(void)\r
-{\r
- if(soundo)\r
- IDirectSoundBuffer_Stop(ppbufw);\r
-}\r
-\r
-#include "wave.c"\r