diff --git a/desmume/src/SPU.cpp b/desmume/src/SPU.cpp index 3ee28884f..3920c1ac0 100644 --- a/desmume/src/SPU.cpp +++ b/desmume/src/SPU.cpp @@ -318,7 +318,7 @@ void SPU_struct::ShutUp() static FORCEINLINE void adjust_channel_timer(channel_struct *chan) { - chan->sampinc = (((double)ARM7_CLOCK) / (44100 * 2)) / (double)(0x10000 - chan->timer); + chan->sampinc = (((double)ARM7_CLOCK) / (DESMUME_SAMPLE_RATE * 2)) / (double)(0x10000 - chan->timer); } void SPU_struct::KeyOn(int channel) @@ -870,7 +870,7 @@ static void SPU_MixAudio(bool actuallyMix, SPU_struct *SPU, int length) static const int dots_per_clock = 6; static const int dots_per_hline = 355; static const double time_per_hline = (double)1.0/((double)ARM7_CLOCK/dots_per_clock/dots_per_hline); -static const double samples_per_hline = time_per_hline * 44100; +static const double samples_per_hline = time_per_hline * DESMUME_SAMPLE_RATE; int spu_core_samples = 0; void SPU_Emulate_core() { @@ -910,6 +910,7 @@ void SPU_Emulate_user(bool mix) samplesOutput = (SPU_MixAudio(mix,SPU_user,audiosize), audiosize); SNDCore->UpdateAudio(SPU_user->outbuf, samplesOutput); + WAV_WavSoundUpdate(SPU_user->outbuf, samplesOutput, WAVMODE_USER); } } @@ -940,7 +941,7 @@ SoundInterface_struct SNDDummy = { int SNDDummyInit(int buffersize) { return 0; } void SNDDummyDeInit() {} void SNDDummyUpdateAudio(s16 *buffer, u32 num_samples) { } -u32 SNDDummyGetAudioSpace() { return 740; } +u32 SNDDummyGetAudioSpace() { return DESMUME_SAMPLE_RATE/60 + 5; } void SNDDummyMuteAudio() {} void SNDDummyUnMuteAudio() {} void SNDDummySetVolume(int volume) {} @@ -992,7 +993,7 @@ bool WavWriter::open(const std::string & fname) fmt.chunk.size = 16; // we'll fix this at the end fmt.compress = 1; // PCM fmt.numchan = 2; // Stereo - fmt.rate = 44100; + fmt.rate = DESMUME_SAMPLE_RATE; fmt.bitspersample = 16; fmt.blockalign = fmt.bitspersample / 8 * fmt.numchan; fmt.bytespersec = fmt.rate * fmt.blockalign; @@ -1044,26 +1045,33 @@ void WAV_End() wavWriter.close(); } -bool WAV_Begin(const char* fname) +bool WAV_Begin(const char* fname, WAVMode mode) { WAV_End(); if(!wavWriter.open(fname)) return false; + if(mode == WAVMODE_ANY) + mode = WAVMODE_CORE; + wavWriter.mode = mode; + driver->USR_InfoMessage("WAV recording started."); return true; } -bool WAV_IsRecording() +bool WAV_IsRecording(WAVMode mode) { - return wavWriter.isRecording(); + if(wavWriter.mode == mode || mode == WAVMODE_ANY) + return wavWriter.isRecording(); + return false; } -void WAV_WavSoundUpdate(void* soundData, int numSamples) +void WAV_WavSoundUpdate(void* soundData, int numSamples, WAVMode mode) { - wavWriter.update(soundData, numSamples); + if(wavWriter.mode == mode || mode == WAVMODE_ANY) + wavWriter.update(soundData, numSamples); } diff --git a/desmume/src/SPU.h b/desmume/src/SPU.h index 252ff53fc..387c4a278 100644 --- a/desmume/src/SPU.h +++ b/desmume/src/SPU.h @@ -149,6 +149,13 @@ extern int spu_core_samples; void spu_savestate(EMUFILE* os); bool spu_loadstate(EMUFILE* is, int size); +enum WAVMode +{ + WAVMODE_ANY = -1, + WAVMODE_CORE = 0, + WAVMODE_USER = 1 +}; + class WavWriter { public: @@ -157,14 +164,19 @@ public: void close(); void update(void* soundData, int numSamples); bool isRecording() const; + WAVMode mode; private: FILE *spufp; }; - void WAV_End(); -bool WAV_Begin(const char* fname); -bool WAV_IsRecording(); -void WAV_WavSoundUpdate(void* soundData, int numSamples); +bool WAV_Begin(const char* fname, WAVMode mode=WAVMODE_CORE); +bool WAV_IsRecording(WAVMode mode=WAVMODE_ANY); +void WAV_WavSoundUpdate(void* soundData, int numSamples, WAVMode mode=WAVMODE_CORE); + +// we should make this configurable eventually +// but at least defining it somewhere is probably a step in the right direction +#define DESMUME_SAMPLE_RATE 44100 +//#define DESMUME_SAMPLE_RATE 48000 #endif diff --git a/desmume/src/metaspu/SndOut.h b/desmume/src/metaspu/SndOut.h index 65252cbe0..6b71bcda5 100644 --- a/desmume/src/metaspu/SndOut.h +++ b/desmume/src/metaspu/SndOut.h @@ -80,8 +80,11 @@ static const int SndOutVolumeShift = 0; // is too problematic. :) //this is hardcoded differently for metaspu //edit - zeromus 23-oct-2009 -//static const int SampleRate = 48000; -static const int SampleRate = 44100; +////static const int SampleRate = 48000; +//static const int SampleRate = 44100; +//edit - nitsuja: make it use the global sample rate define +#include "..\SPU.h" +static const int SampleRate = DESMUME_SAMPLE_RATE; extern int FindOutputModuleById( const wchar_t* omodid ); diff --git a/desmume/src/windows/aviout.cpp b/desmume/src/windows/aviout.cpp index a6cb1f0e5..208a02ad6 100644 --- a/desmume/src/windows/aviout.cpp +++ b/desmume/src/windows/aviout.cpp @@ -26,6 +26,7 @@ #include "gfx3d.h" #include "aviout.h" #include "../GPU_osd.h" +#include "../SPU.h" #include #include @@ -80,7 +81,7 @@ static struct AVIFile long tBytes, ByteBuffer; - u8 audio_buffer[44100*2*2]; // 1 second buffer + u8 audio_buffer[DESMUME_SAMPLE_RATE*2*2]; // 1 second buffer int audio_buffer_pos; } *avi_file = NULL; @@ -365,10 +366,10 @@ bool DRV_AviBegin(const char* fname) WAVEFORMATEX wf; wf.cbSize = sizeof(WAVEFORMATEX); - wf.nAvgBytesPerSec = 44100 * 4; + wf.nAvgBytesPerSec = DESMUME_SAMPLE_RATE * 4; wf.nBlockAlign = 4; wf.nChannels = 2; - wf.nSamplesPerSec = 44100; + wf.nSamplesPerSec = DESMUME_SAMPLE_RATE; wf.wBitsPerSample = 16; wf.wFormatTag = WAVE_FORMAT_PCM; diff --git a/desmume/src/windows/hotkey.cpp b/desmume/src/windows/hotkey.cpp index 1b3a06b25..3cd141ce9 100644 --- a/desmume/src/windows/hotkey.cpp +++ b/desmume/src/windows/hotkey.cpp @@ -238,7 +238,7 @@ void HK_DecreaseVolume(int, bool justPressed) void HK_Reset(int, bool justPressed) {ResetGame();} void HK_RecordAVI(int, bool justPressed) { if (AVI_IsRecording()) AviEnd(); else AviRecordTo(); } -void HK_RecordWAV(int, bool justPressed) { if (WAV_IsRecording()) WavEnd(); else WavRecordTo(); } +void HK_RecordWAV(int, bool justPressed) { if (WAV_IsRecording()) WavEnd(); else WavRecordTo(WAVMODE_CORE); } void HK_ToggleFrame(int, bool justPressed) {CommonSettings.hud.FrameCounterDisplay ^= true;} void HK_ToggleFPS(int, bool justPressed) {CommonSettings.hud.FpsDisplay ^= true;} diff --git a/desmume/src/windows/main.cpp b/desmume/src/windows/main.cpp index e069b96e8..cb330b08e 100644 --- a/desmume/src/windows/main.cpp +++ b/desmume/src/windows/main.cpp @@ -140,6 +140,10 @@ void wxTest() { #endif +#ifndef PUBLIC_RELEASE +#define DEVELOPER_MENU_ITEMS +#endif + const int kGapNone = 0; const int kGapBorder = 5; const int kGapNDS = 64; // extremely tilted (but some games seem to use this value) @@ -269,7 +273,7 @@ extern bool userTouchesScreen; /*__declspec(thread)*/ bool inFrameBoundary = false; static int sndcoretype=SNDCORE_DIRECTX; -static int sndbuffersize=735*8; +static int sndbuffersize=DESMUME_SAMPLE_RATE*8/60; static int snd_synchmode=0; static int snd_synchmethod=0; int sndvolume=100; @@ -1481,7 +1485,7 @@ static void StepRunLoop_Core() Lock lock; NDS_exec(); //SPU_Emulate_user(); - win_sound_samplecounter = 735; + win_sound_samplecounter = DESMUME_SAMPLE_RATE/60; } inFrameBoundary = true; DRV_AviVideoUpdate((u16*)GPU_screen); @@ -1844,6 +1848,12 @@ int MenuInit() ResetSaveStateTimes(); +#ifndef DEVELOPER_MENU_ITEMS + // menu items that are only useful for desmume developers (maybe) + HMENU fileMenu = GetSubMenu(mainMenu, 0); + DeleteMenu(fileMenu, IDM_FILE_RECORDUSERSPUWAV, MF_BYCOMMAND); +#endif + return 1; } @@ -2450,7 +2460,7 @@ int _main() #endif LOG("Init sound core\n"); sndcoretype = GetPrivateProfileInt("Sound","SoundCore2", SNDCORE_DIRECTX, IniName); - sndbuffersize = GetPrivateProfileInt("Sound","SoundBufferSize2", 735*8, IniName); + sndbuffersize = GetPrivateProfileInt("Sound","SoundBufferSize2", DESMUME_SAMPLE_RATE*8/60, IniName); CommonSettings.spuInterpolationMode = (SPUInterpolationMode)GetPrivateProfileInt("Sound","SPUInterpolation", 1, IniName); EnterCriticalSection(&win_execute_sync); @@ -3019,7 +3029,7 @@ void WavEnd() } //Shows an Open File menu and starts recording an WAV -void WavRecordTo() +void WavRecordTo(int wavmode) { NDS_Pause(); @@ -3061,7 +3071,7 @@ void WavRecordTo() if(GetSaveFileName(&ofn)) { - WAV_Begin(szChoice); + WAV_Begin(szChoice, (WAVMode)wavmode); } NDS_UnPause(); @@ -3462,6 +3472,9 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM DesEnableMenuItem(mainMenu, IDM_CHEATS_LIST, romloaded); DesEnableMenuItem(mainMenu, IDM_CHEATS_SEARCH, romloaded); //DesEnableMenuItem(mainMenu, IDM_WIFISETTINGS, romloaded); +#ifdef DEVELOPER_MENU_ITEMS + DesEnableMenuItem(mainMenu, IDM_FILE_RECORDUSERSPUWAV, romloaded && !WAV_IsRecording()); +#endif DesEnableMenuItem(mainMenu, IDM_RECORD_MOVIE, (romloaded /*&& movieMode == MOVIEMODE_INACTIVE*/)); DesEnableMenuItem(mainMenu, IDM_PLAY_MOVIE, (romloaded /*&& movieMode == MOVIEMODE_INACTIVE*/)); @@ -4098,8 +4111,16 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM if (WAV_IsRecording()) WAV_End(); else - WavRecordTo(); + WavRecordTo(WAVMODE_CORE); break; +#ifdef DEVELOPER_MENU_ITEMS + case IDM_FILE_RECORDUSERSPUWAV: + if (WAV_IsRecording()) + WAV_End(); + else + WavRecordTo(WAVMODE_USER); + break; +#endif case IDC_STATEREWINDING: if(staterewindingenabled) staterewindingenabled = false; else staterewindingenabled = true; diff --git a/desmume/src/windows/main.h b/desmume/src/windows/main.h index 9bf04986e..2f730455b 100644 --- a/desmume/src/windows/main.h +++ b/desmume/src/windows/main.h @@ -16,7 +16,7 @@ void FrameAdvance(bool state); void ResetGame(); //Resets game (for the menu item & hotkey void AviRecordTo(); void AviEnd(); -void WavRecordTo(); +void WavRecordTo(int wavmode); void WavEnd(); extern bool frameCounterDisplay; diff --git a/desmume/src/windows/resource.h b/desmume/src/windows/resource.h index 783ea6bf7..371dc761c 100644 --- a/desmume/src/windows/resource.h +++ b/desmume/src/windows/resource.h @@ -694,6 +694,7 @@ #define IDM_SCREENSEP_COLORWHITE 40023 #define IDM_SCREENSEP_COLORGRAY 40024 #define IDM_SCREENSEP_COLORBLACK 40025 +#define IDM_FILE_RECORDUSERSPUWAV 40026 #define ID_FILE_RECENTROM 40034 #define IDC_SAVETYPE7 40037 #define IDM_DEFSIZE 40038 diff --git a/desmume/src/windows/resources.rc b/desmume/src/windows/resources.rc index b6e5f947e..d8ff882ca 100644 Binary files a/desmume/src/windows/resources.rc and b/desmume/src/windows/resources.rc differ diff --git a/desmume/src/windows/snddx.cpp b/desmume/src/windows/snddx.cpp index 8bfd35771..0a3ab917b 100755 --- a/desmume/src/windows/snddx.cpp +++ b/desmume/src/windows/snddx.cpp @@ -132,7 +132,7 @@ int SNDDXInit(int buffersize) memset(&wfx, 0, sizeof(wfx)); wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nChannels = 2; - wfx.nSamplesPerSec = 44100; + wfx.nSamplesPerSec = DESMUME_SAMPLE_RATE; wfx.wBitsPerSample = 16; wfx.nBlockAlign = (wfx.wBitsPerSample / 8) * wfx.nChannels; wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; @@ -248,12 +248,12 @@ void SNDDXUpdateAudio(s16 *buffer, u32 num_samples) } else { - samplecounter = win_sound_samplecounter -= 245; - samplecounter_fakecontribution += 245; + samplecounter = win_sound_samplecounter -= DESMUME_SAMPLE_RATE/180; + samplecounter_fakecontribution += DESMUME_SAMPLE_RATE/180; } } - bool silence = (samplecounter<-44100*15/60); //behind by more than a quarter second -> silence + bool silence = (samplecounter<-DESMUME_SAMPLE_RATE*15/60); //behind by more than a quarter second -> silence if(insilence) { @@ -266,6 +266,12 @@ void SNDDXUpdateAudio(s16 *buffer, u32 num_samples) { if(silence) { +#ifndef PUBLIC_RELEASE + extern volatile bool execute; + if(execute) + printf("snddx: emergency cleared sound buffer. (%d, %d, %d)\n", win_sound_samplecounter, num_samples, samplecounter_fakecontribution); +#endif + samplecounter_fakecontribution = 0; insilence = true; SNDDXClearAudioBuffer(); return; @@ -299,13 +305,18 @@ void SNDDXUpdateAudio(s16 *buffer, u32 num_samples) void SNDDXClearAudioBuffer() { + // we shouldn't need to provide 2 buffers since it's 1 contiguous range + // but maybe newer directsound implementations have issues LPVOID buffer1; - DWORD buffer1_size; - HRESULT hr = lpDSB2->Lock(0, 0, &buffer1, &buffer1_size, NULL, NULL, DSBLOCK_ENTIREBUFFER); + LPVOID buffer2; + DWORD buffer1_size, buffer2_size; + HRESULT hr = lpDSB2->Lock(0, 0, &buffer1, &buffer1_size, &buffer2, &buffer2_size, DSBLOCK_ENTIREBUFFER); if(FAILED(hr)) return; memset(buffer1, 0, buffer1_size); - lpDSB2->Unlock(buffer1, buffer1_size, NULL, 0); + if(buffer2) + memset(buffer2, 0, buffer2_size); + lpDSB2->Unlock(buffer1, buffer1_size, buffer2, buffer2_size); }