From 95968f326adbdabf0f825754cab4e586e76c403a Mon Sep 17 00:00:00 2001 From: Benjamin Date: Sat, 18 Jun 2022 00:23:31 +0200 Subject: [PATCH] Probably fix sound and music volume settings by removing code from DSB and moving it to SoundBoard.cpp --- Src/Model3/DSB.cpp | 15 +++--- Src/Model3/DSB.h | 2 + Src/Model3/SoundBoard.cpp | 50 +++++++++++------- Src/OSD/SDL/Audio.cpp | 61 +++++++++++++--------- Src/OSD/SDL/Main.cpp | 107 ++++++++++++++++++++++++++------------ Src/Sound/SCSPLFO.cpp | 10 ++-- 6 files changed, 156 insertions(+), 89 deletions(-) diff --git a/Src/Model3/DSB.cpp b/Src/Model3/DSB.cpp index 30a42ad..ff64da0 100644 --- a/Src/Model3/DSB.cpp +++ b/Src/Model3/DSB.cpp @@ -147,9 +147,7 @@ int CDSBResampler::UpSampleAndMix(INT16 *outL, INT16 *outR, INT16 *inL, INT16 *i // Obtain program volume settings and convert to 24.8 fixed point (0-200 -> 0x00-0x200) musicVol = m_config["MusicVolume"].ValueAs(); - soundVol = m_config["SoundVolume"].ValueAs(); musicVol = (INT32) ((float) 0x100 * (float) musicVol / 100.0f); - soundVol = (INT32) ((float) 0x100 * (float) soundVol / 100.0f); // Scale volume from 0x00-0xFF -> 0x00-0x100 (24.8 fixed point) v[0] = (INT16) ((float) 0x100 * (float) volumeL / 255.0f); @@ -167,8 +165,8 @@ int CDSBResampler::UpSampleAndMix(INT16 *outL, INT16 *outR, INT16 *inL, INT16 *i rightSample = (rightSample*v[0]*musicVol) >> 16; // Apply sound volume setting - leftSoundSample = (outL[outIdx]*soundVol) >> 8; - rightSoundSample = (outR[outIdx]*soundVol) >> 8; + leftSoundSample = outL[outIdx]; + rightSoundSample = outR[outIdx]; // Mix and output outL[outIdx] = MixAndClip(leftSoundSample, leftSample); @@ -185,7 +183,6 @@ int CDSBResampler::UpSampleAndMix(INT16 *outL, INT16 *outR, INT16 *inL, INT16 *i pFrac += (1<<8); nFrac -= (1<<8); inIdx++; // advance samples (for upsampling only; downsampling may advance by more than one -- add delta every loop iteration) - } } @@ -435,7 +432,7 @@ void CDSB1::RunFrame(INT16 *audioL, INT16 *audioR) // DSB code applies SCSP volume, too, so we must still mix memset(mpegL, 0, (32000/60+2)*sizeof(INT16)); memset(mpegR, 0, (32000/60+2)*sizeof(INT16)); - retainedSamples = Resampler.UpSampleAndMix(audioL, audioR, mpegL, mpegR, 0, 0, 44100/60, 32000/60+2, 44100, 32000); + retainedSamples = Resampler.UpSampleAndMix(audioL, audioR, mpegL, mpegR, 0, 0, NUM_SAMPLES_PER_FRAME, 32000/60+2, 44100, 32000); return; } @@ -457,7 +454,7 @@ void CDSB1::RunFrame(INT16 *audioL, INT16 *audioR) // Decode MPEG for this frame MpegDec::DecodeAudio(&mpegL[retainedSamples], &mpegR[retainedSamples], 32000 / 60 - retainedSamples + 2); - retainedSamples = Resampler.UpSampleAndMix(audioL, audioR, mpegL, mpegR, v, v, 44100/60, 32000/60+2, 44100, 32000); + retainedSamples = Resampler.UpSampleAndMix(audioL, audioR, mpegL, mpegR, v, v, NUM_SAMPLES_PER_FRAME, 32000/60+2, 44100, 32000); } void CDSB1::Reset(void) @@ -1001,7 +998,7 @@ void CDSB2::RunFrame(INT16 *audioL, INT16 *audioR) // DSB code applies SCSP volume, too, so we must still mix memset(mpegL, 0, (32000 / 60 + 2) * sizeof(INT16)); memset(mpegR, 0, (32000 / 60 + 2) * sizeof(INT16)); - retainedSamples = Resampler.UpSampleAndMix(audioL, audioR, mpegL, mpegR, volume[0], volume[1], 44100 / 60, 32000 / 60 + 2, 44100, 32000); + retainedSamples = Resampler.UpSampleAndMix(audioL, audioR, mpegL, mpegR, volume[0], volume[1], NUM_SAMPLES_PER_FRAME, 32000 / 60 + 2, 44100, 32000); return; } @@ -1072,7 +1069,7 @@ void CDSB2::RunFrame(INT16 *audioL, INT16 *audioR) break; } - retainedSamples = Resampler.UpSampleAndMix(audioL, audioR, leftChannelSource, rightChannelSource, volL, volR, 44100 / 60, 32000 / 60 + 2, 44100, 32000); + retainedSamples = Resampler.UpSampleAndMix(audioL, audioR, leftChannelSource, rightChannelSource, volL, volR, NUM_SAMPLES_PER_FRAME, 32000 / 60 + 2, 44100, 32000); } void CDSB2::Reset(void) diff --git a/Src/Model3/DSB.h b/Src/Model3/DSB.h index f39789b..2c71111 100644 --- a/Src/Model3/DSB.h +++ b/Src/Model3/DSB.h @@ -41,6 +41,8 @@ #define FIFO_STACK_SIZE 0x100 #define FIFO_STACK_SIZE_MASK (FIFO_STACK_SIZE - 1) +#define NUM_SAMPLES_PER_FRAME (44100/60) + /****************************************************************************** Resampling diff --git a/Src/Model3/SoundBoard.cpp b/Src/Model3/SoundBoard.cpp index 2ae6cff..1758df0 100644 --- a/Src/Model3/SoundBoard.cpp +++ b/Src/Model3/SoundBoard.cpp @@ -67,6 +67,18 @@ static FILE *soundFP; #endif +// Offsets of memory regions within sound board's pool +#define OFFSET_RAM1 0 // 1 MB SCSP1 RAM +#define OFFSET_RAM2 0x100000 // 1 MB SCSP2 RAM +#define LENGTH_CHANNEL_BUFFER (sizeof(INT16)*NUM_SAMPLES_PER_FRAME) // 1470 bytes (16 bits x 44.1 KHz x 1/60th second) +#define OFFSET_AUDIO_FRONTLEFT 0x200000 // 1470 bytes (16 bits, 44.1 KHz, 1/60th second) left audio channel +#define OFFSET_AUDIO_FRONTRIGHT (OFFSET_AUDIO_FRONTLEFT + LENGTH_CHANNEL_BUFFER) // 1470 bytes right audio channel +#define OFFSET_AUDIO_REARLEFT (OFFSET_AUDIO_FRONTRIGHT + LENGTH_CHANNEL_BUFFER) // 1470 bytes (16 bits, 44.1 KHz, 1/60th second) left audio channel +#define OFFSET_AUDIO_REARRIGHT (OFFSET_AUDIO_REARLEFT + LENGTH_CHANNEL_BUFFER) // 1470 bytes right audio channel + +#define MEMORY_POOL_SIZE (0x100000 + 0x100000 + 4*LENGTH_CHANNEL_BUFFER) + + /****************************************************************************** 68K Address Space Handlers ******************************************************************************/ @@ -350,13 +362,25 @@ bool CSoundBoard::RunFrame(void) } else { - memset(audioFL, 0, 44100/60*sizeof(INT16)); - memset(audioFR, 0, 44100/60*sizeof(INT16)); - memset(audioRL, 0, 44100/60*sizeof(INT16)); - memset(audioRR, 0, 44100/60*sizeof(INT16)); + memset(audioFL, 0, LENGTH_CHANNEL_BUFFER); + memset(audioFR, 0, LENGTH_CHANNEL_BUFFER); + memset(audioRL, 0, LENGTH_CHANNEL_BUFFER); + memset(audioRR, 0, LENGTH_CHANNEL_BUFFER); } - // Run DSB and mix with existing audio + // Compute sound volume as + INT32 soundVol = m_config["SoundVolume"].ValueAs(); + soundVol = (INT32)((float)0x100 * (float)soundVol / 100.0f); + + // Apply sound volume setting to SCSP channels only + for (int i = 0; i < NUM_SAMPLES_PER_FRAME; i++) { + audioFL[i] = (audioFL[i]*soundVol) >> 8; + audioFR[i] = (audioFR[i]*soundVol) >> 8; + audioRL[i] = (audioRL[i]*soundVol) >> 8; + audioRR[i] = (audioRR[i]*soundVol) >> 8; + } + + // Run DSB and mix with existing audio, apply music volume if (NULL != DSB) { // Will need to mix with proper front, rear channels or both (game specific) bool mixDSBWithFront = true; // Everything to front channels for now @@ -368,12 +392,12 @@ bool CSoundBoard::RunFrame(void) } // Output the audio buffers - bool bufferFull = OutputAudio(44100/60, audioFL, audioFR, audioRL, audioRR, m_config["FlipStereo"].ValueAs()); + bool bufferFull = OutputAudio(NUM_SAMPLES_PER_FRAME, audioFL, audioFR, audioRL, audioRR, m_config["FlipStereo"].ValueAs()); #ifdef SUPERMODEL_LOG_AUDIO // Output to binary file INT16 s; - for (int i = 0; i < 44100/60; i++) + for (int i = 0; i < NUM_SAMPLES_PER_FRAME; i++) { s = audioL[i]; fwrite(&s, sizeof(INT16), 1, soundFP); // left channel @@ -452,16 +476,6 @@ void CSoundBoard::AttachDSB(CDSB *DSBPtr) DebugLog("Sound Board connected to DSB\n"); } -// Offsets of memory regions within sound board's pool -#define OFFSET_RAM1 0 // 1 MB SCSP1 RAM -#define OFFSET_RAM2 0x100000 // 1 MB SCSP2 RAM -#define LENGTH_CHANNEL_BUFFER 0x5BE -#define OFFSET_AUDIO_FRONTLEFT 0x200000 // 1470 bytes (16 bits, 44.1 KHz, 1/60th second) left audio channel -#define OFFSET_AUDIO_FRONTRIGHT (OFFSET_AUDIO_FRONTLEFT + LENGTH_CHANNEL_BUFFER) // 1470 bytes right audio channel -#define OFFSET_AUDIO_REARLEFT (OFFSET_AUDIO_FRONTRIGHT + LENGTH_CHANNEL_BUFFER) // 1470 bytes (16 bits, 44.1 KHz, 1/60th second) left audio channel -#define OFFSET_AUDIO_REARRIGHT (OFFSET_AUDIO_REARLEFT + LENGTH_CHANNEL_BUFFER) // 1470 bytes right audio channel - -#define MEMORY_POOL_SIZE (0x100000 + 0x100000 + 4*LENGTH_CHANNEL_BUFFER) bool CSoundBoard::Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr) { @@ -495,7 +509,7 @@ bool CSoundBoard::Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr) M68KGetContext(&M68K); // Initialize SCSPs - SCSP_SetBuffers(audioFL, audioFR, audioRL, audioRR, 44100/60); + SCSP_SetBuffers(audioFL, audioFR, audioRL, audioRR, NUM_SAMPLES_PER_FRAME); SCSP_SetCB(SCSP68KRunCallback, SCSP68KIRQCallback); if (OKAY != SCSP_Init(m_config, 2)) return FAIL; diff --git a/Src/OSD/SDL/Audio.cpp b/Src/OSD/SDL/Audio.cpp index bef1b3f..f0c8000 100755 --- a/Src/OSD/SDL/Audio.cpp +++ b/Src/OSD/SDL/Audio.cpp @@ -89,10 +89,10 @@ static int bytes_per_frame_host = BYTES_PER_FRAME_M3; float BalanceLeftRight = 0; // 0 mid balance, 100: left only, -100:right only float BalanceFrontRear = 0; // 0 mid balance, 100: front only, -100:right only // Mixer factor (depends on values above) -float balanceFactorFrontLeft = 1.0; -float balanceFactorFrontRight = 1.0; -float balanceFactorRearLeft = 1.0; -float balanceFactorRearRight = 1.0; +float balanceFactorFrontLeft = 1.0f; +float balanceFactorFrontRight = 1.0f; +float balanceFactorRearLeft = 1.0f; +float balanceFactorRearRight = 1.0f; static bool enabled = true; // True if sound output is enabled static constexpr unsigned latency = 20; // Audio latency to use (ie size of audio buffer) as percentage of max buffer size @@ -145,10 +145,24 @@ void SetAudioType(Game::AudioTypes type) static INT16 AddAndClampINT16(INT32 x, INT32 y) { INT32 sum = x+y; - if (sum>INT16_MAX) + if (sum > INT16_MAX) { sum = INT16_MAX; - if (sum>1; + if (sum > INT16_MAX) { + sum = INT16_MAX; + } + if (sum < INT16_MIN) { sum = INT16_MIN; + } return (INT16)sum; } @@ -263,10 +277,9 @@ static void MixChannels(unsigned numSamples, INT16* leftFrontBuffer, INT16* righ if (nbHostAudioChannels == 1) { for (unsigned i = 0; i < numSamples; i++) { - // TODO: these should probably be clipped! - //INT16 monovalue = (INT16)(((INT32)leftFrontBuffer[i] + (INT32)rightFrontBuffer[i] + (INT32)leftRearBuffer[i] + (INT32)rightRearBuffer[i])); - INT16 monovalue = AddAndClampINT16(((INT32)leftFrontBuffer[i])*balanceFactorFrontLeft + ((INT32)rightFrontBuffer[i])*balanceFactorFrontRight, - ((INT32)leftRearBuffer[i])*balanceFactorRearLeft + ((INT32)rightRearBuffer[i])*balanceFactorRearRight); + INT16 monovalue = MixINT16( + MixINT16((INT32)(leftFrontBuffer[i] * balanceFactorFrontLeft), (INT32)(rightFrontBuffer[i] * balanceFactorFrontRight)), + MixINT16((INT32)(leftRearBuffer[i] * balanceFactorRearLeft), (INT32)(rightRearBuffer[i] * balanceFactorRearRight))); *p++ = monovalue; } } else { @@ -282,8 +295,8 @@ static void MixChannels(unsigned numSamples, INT16* leftFrontBuffer, INT16* righ // Now order channels according to audio type if (nbHostAudioChannels == 2) { for (unsigned i = 0; i < numSamples; i++) { - INT16 leftvalue = AddAndClampINT16(leftFrontBuffer[i]*balanceFactorFrontLeft, leftRearBuffer[i]*balanceFactorRearLeft); - INT16 rightvalue = AddAndClampINT16(rightFrontBuffer[i]*balanceFactorFrontRight, rightRearBuffer[i]*balanceFactorRearRight); + INT16 leftvalue = MixINT16((INT32)(leftFrontBuffer[i] * balanceFactorFrontLeft), (INT32)(leftRearBuffer[i] * balanceFactorRearLeft)); + INT16 rightvalue = MixINT16((INT32)(rightFrontBuffer[i]*balanceFactorFrontRight), (INT32)(rightRearBuffer[i]*balanceFactorRearRight)); if (flipStereo) // swap left and right channels { *p++ = rightvalue; @@ -303,7 +316,7 @@ static void MixChannels(unsigned numSamples, INT16* leftFrontBuffer, INT16* righ // Check game audio type switch (AudioType) { case Game::MONO: { - INT16 monovalue = AddAndClampINT16(AddAndClampINT16(frontLeftValue, frontRightValue), AddAndClampINT16(rearLeftValue, rearRightValue)); + INT16 monovalue = MixINT16(MixINT16(frontLeftValue, frontRightValue), MixINT16(rearLeftValue, rearRightValue)); *p++ = monovalue; *p++ = monovalue; *p++ = monovalue; @@ -312,8 +325,8 @@ static void MixChannels(unsigned numSamples, INT16* leftFrontBuffer, INT16* righ case Game::STEREO_LR: case Game::STEREO_RL: { - INT16 leftvalue = AddAndClampINT16(frontLeftValue, frontRightValue); - INT16 rightvalue = AddAndClampINT16(rearLeftValue, rearRightValue); + INT16 leftvalue = MixINT16(frontLeftValue, frontRightValue); + INT16 rightvalue = MixINT16(rearLeftValue, rearRightValue); if (flipStereo) // swap left and right channels { *p++ = rightvalue; @@ -365,10 +378,10 @@ static void MixChannels(unsigned numSamples, INT16* leftFrontBuffer, INT16* righ case Game::QUAD_1_LR_2_FR_MIX: // Split mix: one goes to left/right, other front/rear (mono) // =>Remix all! - INT16 newfrontLeftValue = AddAndClampINT16(frontLeftValue, rearLeftValue); - INT16 newfrontRightValue = AddAndClampINT16(frontLeftValue, rearRightValue); - INT16 newrearLeftValue = AddAndClampINT16(frontRightValue, rearLeftValue); - INT16 newrearRightValue = AddAndClampINT16(frontRightValue, rearRightValue); + INT16 newfrontLeftValue = MixINT16(frontLeftValue, rearLeftValue); + INT16 newfrontRightValue = MixINT16(frontLeftValue, rearRightValue); + INT16 newrearLeftValue = MixINT16(frontRightValue, rearLeftValue); + INT16 newrearRightValue = MixINT16(frontRightValue, rearRightValue); if (flipStereo) // swap left and right channels { @@ -443,10 +456,10 @@ bool OpenAudio(const Util::Config::Node& config) balancefr *= 0.01f; BalanceFrontRear = balancefr; - balanceFactorFrontLeft = (BalanceLeftRight<0.0?1.0+BalanceLeftRight:1.0)*(BalanceFrontRear<0?1.0+BalanceFrontRear:1.0); - balanceFactorFrontRight = (BalanceLeftRight>0.0?1.0-BalanceLeftRight:1.0)*(BalanceFrontRear<0?1.0+BalanceFrontRear:1.0); - balanceFactorRearLeft = (BalanceLeftRight<0.0?1.0+BalanceLeftRight:1.0)*(BalanceFrontRear>0?1.0-BalanceFrontRear:1.0); - balanceFactorRearRight = (BalanceLeftRight>0.0?1.0-BalanceLeftRight:1.0)*(BalanceFrontRear>0?1.0-BalanceFrontRear:1.0); + balanceFactorFrontLeft = (BalanceLeftRight < 0.f ? 1.f + BalanceLeftRight : 1.f) * (BalanceFrontRear < 0 ? 1.f + BalanceFrontRear : 1.f); + balanceFactorFrontRight = (BalanceLeftRight > 0.f ? 1.f - BalanceLeftRight : 1.f) * (BalanceFrontRear < 0 ? 1.f + BalanceFrontRear : 1.f); + balanceFactorRearLeft = (BalanceLeftRight < 0.f ? 1.f + BalanceLeftRight : 1.f) * (BalanceFrontRear > 0 ? 1.f - BalanceFrontRear : 1.f); + balanceFactorRearRight = (BalanceLeftRight > 0.f ? 1.f - BalanceLeftRight : 1.f) * (BalanceFrontRear > 0 ? 1.f - BalanceFrontRear : 1.f); // Set up audio specification SDL_AudioSpec desired; @@ -530,7 +543,7 @@ bool OutputAudio(unsigned numSamples, INT16* leftFrontBuffer, INT16* rightFrontB INT16* src; // Number of samples should never be more than max number of samples per frame - if (numSamples > samples_per_frame_host) + if (numSamples > (unsigned)samples_per_frame_host) numSamples = samples_per_frame_host; // Mix together left and right channels into single chunk of data diff --git a/Src/OSD/SDL/Main.cpp b/Src/OSD/SDL/Main.cpp index 43f28fc..ced4661 100644 --- a/Src/OSD/SDL/Main.cpp +++ b/Src/OSD/SDL/Main.cpp @@ -58,17 +58,18 @@ #include #include +#ifdef SUPERMODEL_WIN32 +#include "DirectInputSystem.h" +#include "WinOutputs.h" +#include "NetOutputs.h" +#endif + #include "Supermodel.h" #include "Util/Format.h" #include "Util/NewConfig.h" #include "Util/ConfigBuilders.h" #include "GameLoader.h" #include "SDLInputSystem.h" -#ifdef SUPERMODEL_WIN32 -#include "DirectInputSystem.h" -#include "WinOutputs.h" -#include "NetOutputs.h" -#endif #include "SDLIncludes.h" #include "Debugger/SupermodelDebugger.h" #include "Graphics/Legacy3D/Legacy3D.h" @@ -824,16 +825,52 @@ void EndFrameVideo() SDL_GL_SwapWindow(s_window); } -static void SuperSleep(UINT32 time) + +/****************************************************************************** + Frame Timing +******************************************************************************/ + +static uint64_t s_perfCounterFrequency = 0; + +static uint64_t GetDesiredRefreshRateMilliHz() +{ + // The refresh rate is expressed as mHz (millihertz -- Hz * 1000) in order to + // be expressable as an integer. E.g.: 57.524 Hz -> 57524 mHz. + float refreshRateHz = std::abs(s_runtime_config["RefreshRate"].ValueAs()); + uint64_t refreshRateMilliHz = uint64_t(1000.0f * refreshRateHz); + return refreshRateMilliHz; +} + +static void SuperSleepUntil(uint64_t target) { - UINT32 start = SDL_GetTicks(); - UINT32 tics = start; + uint64_t time = SDL_GetPerformanceCounter(); - while (start + time > tics) { - tics = SDL_GetTicks(); + // If we're ahead of the target, we're done + if (time > target) + { + return; + } + + // Compute the whole number of millis to sleep. Because OS sleep is not accurate, + // we actually sleep for one less and will spin-wait for the final millisecond. + int32_t numWholeMillisToSleep = int32_t((target - time) * 1000 / s_perfCounterFrequency); + numWholeMillisToSleep -= 1; + if (numWholeMillisToSleep > 0) + { + SDL_Delay(numWholeMillisToSleep); } + + // Spin until requested time + volatile uint64_t now; + int32_t remain; + do + { + now = SDL_GetPerformanceCounter(); + remain = int32_t((target - now)); + } while (remain>0); } + /****************************************************************************** Main Program Loop ******************************************************************************/ @@ -847,7 +884,7 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In { #endif // SUPERMODEL_DEBUGGER std::string initialState = s_runtime_config["InitStateFile"].ValueAs(); - unsigned prevFPSTicks; + uint64_t prevFPSTicks; unsigned fpsFramesElapsed; bool gameHasLightguns = false; bool quit = false; @@ -903,6 +940,11 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In if (Outputs != NULL) Model3->AttachOutputs(Outputs); + // Frame timing + s_perfCounterFrequency = SDL_GetPerformanceFrequency(); + uint64_t perfCountPerFrame = s_perfCounterFrequency * 1000 / GetDesiredRefreshRateMilliHz(); + uint64_t nextTime = 0; + // Initialize the renderers CRender2D *Render2D = new CRender2D(s_runtime_config); IRender3D *Render3D = s_runtime_config["New3DEngine"].ValueAs() ? ((IRender3D *) new New3D::CNew3D(s_runtime_config, Model3->GetGame().name)) : ((IRender3D *) new Legacy3D::CLegacy3D(s_runtime_config)); @@ -934,7 +976,7 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In // Emulate! fpsFramesElapsed = 0; - prevFPSTicks = SDL_GetTicks(); + prevFPSTicks = SDL_GetPerformanceCounter(); quit = false; paused = false; dumpTimings = false; @@ -947,8 +989,6 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In #endif while (!quit) { - auto startTime = SDL_GetTicks(); - // Render if paused, otherwise run a frame if (paused) Model3->RenderFrame(); @@ -1224,32 +1264,29 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In } #endif // SUPERMODEL_DEBUGGER + // Refresh rate (frame limiting) + if (paused || s_runtime_config["Throttle"].ValueAs()) + { + SuperSleepUntil(nextTime); + nextTime = SDL_GetPerformanceCounter() + perfCountPerFrame; + } - // Frame rate and limiting - unsigned currentFPSTicks = SDL_GetTicks(); + // Measure frame rate + uint64_t currentFPSTicks = SDL_GetPerformanceCounter(); if (s_runtime_config["ShowFrameRate"].ValueAs()) { - ++fpsFramesElapsed; - if((currentFPSTicks-prevFPSTicks) >= 1000) // update FPS every 1 second (each tick is 1 ms) + fpsFramesElapsed += 1; + uint64_t measurementTicks = currentFPSTicks - prevFPSTicks; + if (measurementTicks >= s_perfCounterFrequency) // update FPS every 1 second (s_perfCounterFrequency is how many perf ticks in one second) { - sprintf(titleStr, "%s - %1.1f FPS%s", baseTitleStr, (float)fpsFramesElapsed/((float)(currentFPSTicks-prevFPSTicks)/1000.0f), paused ? " (Paused)" : ""); + float fps = float(fpsFramesElapsed) / (float(measurementTicks) / float(s_perfCounterFrequency)); + sprintf(titleStr, "%s - %1.3f FPS%s", baseTitleStr, fps, paused ? " (Paused)" : ""); SDL_SetWindowTitle(s_window, titleStr); prevFPSTicks = currentFPSTicks; // reset tick count fpsFramesElapsed = 0; // reset frame count } } - if (paused || s_runtime_config["Throttle"].ValueAs()) - { - UINT32 endTime = SDL_GetTicks(); - UINT32 diff = endTime - startTime; - UINT32 frameTime = (UINT32)(1000 / 60.f); // 60 fps, we could roll with 57.5? that would be a jerk fest on 60hz screens though - - if (diff < frameTime) { - SuperSleep(frameTime - diff); - } - } - if (dumpTimings && !paused) { CModel3 *M = dynamic_cast(Model3); @@ -1426,6 +1463,7 @@ static Util::Config::Node DefaultConfig() config.Set("WideBackground", false); config.Set("VSync", true); config.Set("Throttle", true); + config.Set("RefreshRate", 60.0f); config.Set("ShowFrameRate", false); config.Set("Crosshairs", int(0)); config.Set("FlipStereo", false); @@ -1476,8 +1514,8 @@ static Util::Config::Node DefaultConfig() static void Title(void) { puts("Supermodel: A Sega Model 3 Arcade Emulator (Version " SUPERMODEL_VERSION ")"); - puts("Copyright 2011-2021 by Bart Trzynadlowski, Nik Henson, Ian Curtis,"); - puts(" Harry Tuttle, and Spindizzi\n"); + puts("Copyright 2011-2022 by Bart Trzynadlowski, Nik Henson, Ian Curtis, Harry Tuttle,"); + puts(" Spindizzi, gm_mathew, and njz3\n"); } static void Help(void) @@ -1508,9 +1546,10 @@ static void Help(void) puts(" -wide-bg When wide-screen mode is enabled, also expand the 2D"); puts(" background layer to screen width"); puts(" -stretch Fit viewport to resolution, ignoring aspect ratio"); - puts(" -no-throttle Disable 60 Hz frame rate lock"); + puts(" -no-throttle Disable frame rate lock"); puts(" -vsync Lock to vertical refresh rate [Default]"); puts(" -no-vsync Do not lock to vertical refresh rate"); + puts(" -true-hz Use true Model 3 refresh rate of 57.524 Hz"); puts(" -show-fps Display frame rate in window title bar"); puts(" -crosshairs= Crosshairs configuration for gun games:"); puts(" 0=none [Default], 1=P1 only, 2=P2 only, 3=P1 & P2"); @@ -1730,6 +1769,8 @@ static ParsedCommandLine ParseCommandLine(int argc, char **argv) } } } + else if (arg == "-true-hz") + cmd_line.config.Set("RefreshRate", 57.524f); else if (arg == "-print-gl-info") cmd_line.print_gl_info = true; else if (arg == "-config-inputs") diff --git a/Src/Sound/SCSPLFO.cpp b/Src/Sound/SCSPLFO.cpp index 3d19eaa..e3350d8 100644 --- a/Src/Sound/SCSPLFO.cpp +++ b/Src/Sound/SCSPLFO.cpp @@ -49,10 +49,10 @@ struct _LFO static int PLFO_TRI[256], PLFO_SQR[256], PLFO_SAW[256], PLFO_NOI[256]; static int ALFO_TRI[256], ALFO_SQR[256], ALFO_SAW[256], ALFO_NOI[256]; -static float LFOFreq[32] = { 0.17,0.19,0.23,0.27,0.34,0.39,0.45,0.55,0.68,0.78,0.92,1.10,1.39,1.60,1.87,2.27, - 2.87,3.31,3.92,4.79,6.15,7.18,8.60,10.8,14.4,17.2,21.5,28.7,43.1,57.4,86.1,172.3 }; -static float ASCALE[8] = { 0.0,0.4,0.8,1.5,3.0,6.0,12.0,24.0 }; -static float PSCALE[8] = { 0.0,7.0,13.5,27.0,55.0,112.0,230.0,494 }; +static float LFOFreq[32] = { 0.17f, 0.19f, 0.23f, 0.27f, 0.34f, 0.39f, 0.45f, 0.55f, 0.68f, 0.78f, 0.92f, 1.10f, 1.39f, 1.60f, 1.87f, 2.27f, + 2.87f, 3.31f, 3.92f, 4.79f, 6.15f, 7.18f, 8.60f, 10.8f, 14.4f, 17.2f, 21.5f, 28.7f, 43.1f, 57.4f, 86.1f, 172.3f }; +static float ASCALE[8] = { 0.0f, 0.4f, 0.8f, 1.5f, 3.0f, 6.0f, 12.0f, 24.0f }; +static float PSCALE[8] = { 0.0f, 7.0f, 13.5f, 27.0f, 55.0f, 112.0f, 230.0f, 494.0f }; static int PSCALES[8][256]; static int ASCALES[8][256]; @@ -151,7 +151,7 @@ signed int inline ALFO_Step(struct _LFO *LFO) void LFO_ComputeStep(struct _LFO *LFO, UINT32 LFOF, UINT32 LFOWS, UINT32 LFOS, int ALFO) { - float step = (float)LFOFreq[LFOF] * 256.0 / (float)44100.0; + float step = (float)LFOFreq[LFOF] * 256.0f / (float)44100.0f; LFO->phase_step = (unsigned int)((float)(1 << LFO_SHIFT)*step); if (ALFO) {