/* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2002 Xodnizel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ LPDIRECTSOUND ppDS=0; /* DirectSound object. */ LPDIRECTSOUNDBUFFER ppbuf=0; /* Primary buffer object. */ LPDIRECTSOUNDBUFFER ppbufsec=0; /* Secondary buffer object. */ LPDIRECTSOUNDBUFFER ppbufw; /* Buffer to actually write to. */ 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. */ DSBUFFERDESC DSBufferDesc; WAVEFORMATEX wfa; WAVEFORMATEX wf; int bittage; static int mute=0; /* TODO: add to config? add to GUI. */ void TrashSound(void) { FCEUI_Sound(0); if(ppbufsec) { IDirectSoundBuffer_Stop(ppbufsec); IDirectSoundBuffer_Release(ppbufsec); ppbufsec=0; } if(ppbuf) { IDirectSoundBuffer_Stop(ppbuf); IDirectSoundBuffer_Release(ppbuf); ppbuf=0; } if(ppDS) { IDirectSound_Release(ppDS); ppDS=0; } } void CheckDStatus(void) { DWORD status; status=0; IDirectSoundBuffer_GetStatus(ppbufw, &status); if(status&DSBSTATUS_BUFFERLOST) { IDirectSoundBuffer_Restore(ppbufw); } if(!(status&DSBSTATUS_PLAYING)) { ToWritePos=0; IDirectSoundBuffer_SetFormat(ppbufw,&wf); IDirectSoundBuffer_Play(ppbufw,0,0,DSBPLAY_LOOPING); } } static uint32 RawCanWrite(void) { DWORD CurWritePos,CurPlayPos=0; CheckDStatus(); CurWritePos=0; if(IDirectSoundBuffer_GetCurrentPosition(ppbufw,&CurPlayPos,&CurWritePos)==DS_OK) { // FCEU_DispMessage("%8d",(CurWritePos-CurPlayPos)); } CurWritePos=(CurPlayPos+BufHowMuch)%DSBufferSize; /* If the current write pos is >= half the buffer size less than the to write pos, assume DirectSound has wrapped around. */ if(((int32)ToWritePos-(int32)CurWritePos) >= (DSBufferSize/2)) { CurWritePos+=DSBufferSize; //FCEU_printf("Fixit: %d,%d,%d\n",ToWritePos,CurWritePos,CurWritePos-DSBufferSize); } if(ToWritePos BufHowMuch) /* Oopsie. Severe buffer overflow... */ { //FCEU_printf("Ack"); ToWritePos=CurWritePos%DSBufferSize; } return(CurWritePos-ToWritePos); } else return(0); } int32 GetWriteSound(void) { if(!soundo) return 0; return(RawCanWrite() >> bittage); } int32 GetMaxSound(void) { return( BufHowMuch >> bittage); } static int RawWrite(void *data, uint32 len) { //uint32 cw; //mbg merge 7/17/06 removed //printf("Pre: %d\n",SexyALI_DSound_RawCanWrite(device)); //fflush(stdout); if(!soundo) return 0; CheckDStatus(); /* 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}; //mbg merge 7/17/06 changed to uint //mbg merge 7/18/06 was causing a crash when fastforwarding unless this was initialized to len uint32 curlen=len; // THIS LIMITS THE EMULATION SPEED if((!NoWaiting) || (soundoptions&SO_OLDUP)) while(!(curlen=RawCanWrite())) { Sleep(1); } if(curlen>len) curlen=len; if(DS_OK == IDirectSoundBuffer_Lock(ppbufw,ToWritePos,curlen,&LockPtr[0],&LockLen[0],&LockPtr[1],&LockLen[1],0)) { } if(LockPtr[1] != 0 && LockPtr[1] != LockPtr[0]) { if(mute) { if(bittage) { memset(LockPtr[0], 0, LockLen[0]); memset(LockPtr[1], 0, len-LockLen[0]); } else { memset(LockPtr[0], 0x80, LockLen[0]); memset(LockPtr[1], 0x80, len-LockLen[0]); } } else { /* not mute */ memcpy(LockPtr[0],data,LockLen[0]); memcpy(LockPtr[1],(char*)data+LockLen[0],len-LockLen[0]); //mbg merge 7/17/06 added cast } } else if(LockPtr[0]) { if(mute) { if(bittage) memset(LockPtr[0], 0, curlen); else memset(LockPtr[0], 0x80, curlen); } else { /* not mute */ memcpy(LockPtr[0],data,curlen); } } IDirectSoundBuffer_Unlock(ppbufw,LockPtr[0],LockLen[0],LockPtr[1],LockLen[1]); ToWritePos=(ToWritePos+curlen)%DSBufferSize; len-=curlen; data=(uint8 *)data+curlen; //mbg merge 7/17/06 reworked to be type proper if(len && !NoWaiting && (fps_scale <= 256 || (soundoptions&SO_OLDUP))) Sleep(1); // do some extra sleeping if we think there's time and we're not scaling up the FPS or in turbo mode } // end while(len) loop return(1); } int silencer=0; int FCEUD_WriteSoundData(int32 *Buffer, int scale, int Count) { #define WSD_BUFSIZE (2 * 96000 / 50) int P; int iCount=0; static int16 MBuffer[WSD_BUFSIZE*2]; if(!(soundoptions&SO_OLDUP)) { if(FCEUI_EmulationPaused()) memset(MBuffer, 0, WSD_BUFSIZE); // slow and/or unnecessary if(FCEUI_EmulationPaused()) scale >>= 1; // limit frequency change to between 50% and 200% if(scale > 512) scale = 512; if(scale < 128) scale = 128; } // for(;Count>0;Count-=WSD_BUFSIZE) { int amt = (soundoptions&SO_OLDUP) ? Count : (Count > WSD_BUFSIZE ? WSD_BUFSIZE : Count); if(!bittage) { if(silencer) for(P=0;P>8))^128; else if(scale == 256) // exactly 100% speed for(P=0;P>8))^128; else // change sound frequency for(P=0;P>8))^128; RawWrite(MBuffer,amt); } else // force 8-bit sound is off: { if(silencer) for(P=0;P>16)) switch(wParam&0xFFFF) { case 1: gornk: DestroyWindow(hwndDlg); uug=0; break; } } return 0; } void ConfigSound(void) { if(!uug) uug=CreateDialog(fceu_hInstance,"SOUNDCONFIG",0,SoundConCallB); else SetFocus(uug); } void StopSound(void) { if(soundo) { VOID *LockPtr=0; DWORD LockLen=0; if(DS_OK == IDirectSoundBuffer_Lock(ppbufw,0,DSBufferSize,&LockPtr,&LockLen,0,0,0)) { //FCEUD_PrintError("K"); if(bittage) memset(LockPtr, 0, LockLen); else memset(LockPtr, 0x80, LockLen); IDirectSoundBuffer_Unlock(ppbufw,LockPtr,LockLen,0,0); } //IDirectSoundBuffer_Stop(ppbufw); } } void FCEUD_SoundToggle(void) { if(mute) { mute=0; FCEU_DispMessage("Sound mute off."); } else { mute=1; StopSound(); FCEU_DispMessage("Sound mute on."); } } void FCEUD_SoundVolumeAdjust(int n) { switch(n) { case -1: soundvolume-=10; if(soundvolume<0) soundvolume=0; break; case 0: soundvolume=100; break; case 1: soundvolume+=10; if(soundvolume>150) soundvolume=150; break; } mute=0; FCEUI_SetSoundVolume(soundvolume); FCEU_DispMessage("Sound volume %d.", soundvolume); } #include "wave.c"