/* 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>= 1; // limit frequency change to between 50% and 200% //if(scale > 512) scale = 512; //if(scale < 128) scale = 128; //} int silence = FCEUI_EmulationPaused() | silencer; for(;Count>0;Count-=WSD_BUFSIZE) { //int amt = (soundoptions&SO_OLDUP) ? Count : (Count > WSD_BUFSIZE ? WSD_BUFSIZE : Count); int amt = (Count > WSD_BUFSIZE ? WSD_BUFSIZE : Count); if(!bittage) { if(silence) 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(silence) for(P=0;P>1; for(P=0;P>8)<<1]; mix += ((src[((loc>>8)+1)<<1]-mix)*(loc&255))>>8; dest[P<<1] = mix; } } RawWrite(MBuffer,amt * 2); } iCount+=amt; } // FCEUI_AviSoundUpdate((void*)MBuffer, Count); return iCount; } */ int InitSound() { DSCAPS dscaps; DSBCAPS dsbcaps; memset(&wf,0x00,sizeof(wf)); wf.wFormatTag = WAVE_FORMAT_PCM; wf.nChannels = 1; wf.nSamplesPerSec = soundrate; ddrval=DirectSoundCreate(0,&ppDS,0); if (ddrval != DS_OK) { FCEUD_PrintError("DirectSound: Error creating DirectSound object."); return 0; } if(soundoptions&SO_SECONDARY) { trysecondary: ddrval=IDirectSound_SetCooperativeLevel(ppDS,hAppWnd,DSSCL_PRIORITY); if (ddrval != DS_OK) { FCEUD_PrintError("DirectSound: Error setting cooperative level to DDSCL_PRIORITY."); TrashSound(); return 0; } } else { ddrval=IDirectSound_SetCooperativeLevel(ppDS,hAppWnd,DSSCL_WRITEPRIMARY); if (ddrval != DS_OK) { FCEUD_PrintError("DirectSound: Error setting cooperative level to DDSCL_WRITEPRIMARY. Forcing use of secondary sound buffer and trying again..."); soundoptions|=SO_SECONDARY; goto trysecondary; } } memset(&dscaps,0x00,sizeof(dscaps)); dscaps.dwSize=sizeof(dscaps); ddrval=IDirectSound_GetCaps(ppDS,&dscaps); if(ddrval!=DS_OK) { FCEUD_PrintError("DirectSound: Error getting capabilities."); return 0; } if(dscaps.dwFlags&DSCAPS_EMULDRIVER) 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."); IDirectSound_Compact(ppDS); memset(&DSBufferDesc,0x00,sizeof(DSBUFFERDESC)); DSBufferDesc.dwSize=sizeof(DSBufferDesc); if(soundoptions&SO_SECONDARY) DSBufferDesc.dwFlags=DSBCAPS_PRIMARYBUFFER; else DSBufferDesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_GETCURRENTPOSITION2; ddrval=IDirectSound_CreateSoundBuffer(ppDS,&DSBufferDesc,&ppbuf,0); if (ddrval != DS_OK) { FCEUD_PrintError("DirectSound: Error creating primary buffer."); TrashSound(); return 0; } memset(&wfa,0x00,sizeof(wfa)); if(soundoptions&SO_FORCE8BIT) bittage=0; else { bittage=1; if( (!(dscaps.dwFlags&DSCAPS_PRIMARY16BIT) && !(soundoptions&SO_SECONDARY)) || (!(dscaps.dwFlags&DSCAPS_SECONDARY16BIT) && (soundoptions&SO_SECONDARY))) { FCEUD_PrintError("DirectSound: 16-bit sound is not supported. Forcing 8-bit sound."); bittage=0; soundoptions|=SO_FORCE8BIT; } } wf.wBitsPerSample=8<>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.cpp"