diff --git a/CHANGES b/CHANGES index 77f2e3633..b0f650478 100644 --- a/CHANGES +++ b/CHANGES @@ -17,6 +17,7 @@ Features: - Screensaver can now be suspended while a game is running - Load/save the most recent savestate slot - Support varible speed (PWM) rumble + - Ability to cap fast forward speed Bugfixes: - ARM7: Fix SWI and IRQ timings - GBA Audio: Force audio FIFOs to 32-bit diff --git a/src/platform/qt/GameController.cpp b/src/platform/qt/GameController.cpp index 0f1988666..8f22831af 100644 --- a/src/platform/qt/GameController.cpp +++ b/src/platform/qt/GameController.cpp @@ -41,8 +41,10 @@ GameController::GameController(QObject* parent) , m_audioProcessor(AudioProcessor::create()) , m_videoSync(VIDEO_SYNC) , m_audioSync(AUDIO_SYNC) + , m_fpsTarget(-1) , m_turbo(false) , m_turboForced(false) + , m_turboSpeed(-1) , m_inputController(nullptr) , m_multiplayer(nullptr) , m_stateSlot(1) @@ -99,6 +101,7 @@ GameController::GameController(QObject* parent) context->gba->rtcSource = &controller->m_rtc; context->gba->rumble = controller->m_inputController->rumble(); context->gba->rotationSource = controller->m_inputController->rotationSource(); + controller->m_fpsTarget = context->fpsTarget; controller->gameStarted(context); }; @@ -487,7 +490,11 @@ void GameController::setAudioBufferSamples(int samples) { void GameController::setFPSTarget(float fps) { threadInterrupt(); + m_fpsTarget = fps; m_threadContext.fpsTarget = fps; + if (m_turbo && m_turboSpeed > 0) { + m_threadContext.fpsTarget *= m_turboSpeed; + } redoSamples(m_audioProcessor->getBufferSamples()); threadContinue(); QMetaObject::invokeMethod(m_audioProcessor, "inputParametersChanged"); @@ -577,9 +584,30 @@ void GameController::setTurbo(bool set, bool forced) { } m_turbo = set; m_turboForced = set && forced; + enableTurbo(); +} + +void GameController::setTurboSpeed(float ratio) { + m_turboSpeed = ratio; + enableTurbo(); +} + +void GameController::enableTurbo() { threadInterrupt(); - m_threadContext.sync.audioWait = set ? false : m_audioSync; - m_threadContext.sync.videoFrameWait = set ? false : m_videoSync; + if (!m_turbo) { + m_threadContext.fpsTarget = m_fpsTarget; + m_threadContext.sync.audioWait = m_audioSync; + m_threadContext.sync.videoFrameWait = m_videoSync; + redoSamples(m_audioProcessor->getBufferSamples()); + } else if (m_turboSpeed <= 0) { + m_threadContext.sync.audioWait = false; + m_threadContext.sync.videoFrameWait = false; + } else { + m_threadContext.fpsTarget = m_fpsTarget * m_turboSpeed; + m_threadContext.sync.audioWait = true; + m_threadContext.sync.videoFrameWait = false; + redoSamples(m_audioProcessor->getBufferSamples()); + } threadContinue(); } diff --git a/src/platform/qt/GameController.h b/src/platform/qt/GameController.h index 6c1a164e2..e45e05a4d 100644 --- a/src/platform/qt/GameController.h +++ b/src/platform/qt/GameController.h @@ -121,6 +121,7 @@ public slots: void setVolume(int); void setMute(bool); void setTurbo(bool, bool forced = true); + void setTurboSpeed(float ratio = -1); void setAVStream(GBAAVStream*); void clearAVStream(); void reloadAudioDriver(); @@ -151,6 +152,7 @@ private slots: private: void updateKeys(); void redoSamples(int samples); + void enableTurbo(); uint32_t* m_drawContext; GBAThread m_threadContext; @@ -177,8 +179,10 @@ private: bool m_videoSync; bool m_audioSync; + float m_fpsTarget; bool m_turbo; bool m_turboForced; + float m_turboSpeed; int m_stateSlot; diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index 7adb00cf7..9bd0261d2 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -787,6 +787,19 @@ void Window::setupMenu(QMenuBar* menubar) { connect(turbo, SIGNAL(triggered(bool)), m_controller, SLOT(setTurbo(bool))); addControlledAction(emulationMenu, turbo, "fastForward"); + QMenu* ffspeedMenu = emulationMenu->addMenu(tr("Fast forward speed")); + ConfigOption* ffspeed = m_config->addOption("fastForwardRatio"); + ffspeed->connect([this](const QVariant& value) { + m_controller->setTurboSpeed(value.toFloat()); + }, this); + ffspeed->addValue(tr("Unbounded"), -1.0f, ffspeedMenu); + ffspeed->setValue(QVariant(-1.0f)); + ffspeedMenu->addSeparator(); + for (i = 2; i < 6; ++i) { + ffspeed->addValue(tr("%0x").arg(i), i, ffspeedMenu); + } + m_config->updateOption("fastForwardRatio"); + QAction* rewind = new QAction(tr("Re&wind"), emulationMenu); rewind->setShortcut(tr("`")); connect(rewind, SIGNAL(triggered()), m_controller, SLOT(rewind()));