diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 2ee0a96ede..9191ca0931 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -2,6 +2,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 #include <limits>
+#include <optional>
 #include <vector>
 
 #include "audio_core/audio_out.h"
@@ -88,9 +89,12 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing_, Core::Memor
     stream = audio_out->OpenStream(
         core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
         fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback));
-    process_event = Core::Timing::CreateEvent(
-        fmt::format("AudioRenderer-Instance{}-Process", instance_number),
-        [this](std::uintptr_t, std::chrono::nanoseconds) { ReleaseAndQueueBuffers(); });
+    process_event =
+        Core::Timing::CreateEvent(fmt::format("AudioRenderer-Instance{}-Process", instance_number),
+                                  [this](std::uintptr_t, s64, std::chrono::nanoseconds) {
+                                      ReleaseAndQueueBuffers();
+                                      return std::nullopt;
+                                  });
     for (s32 i = 0; i < NUM_BUFFERS; ++i) {
         QueueMixedBuffer(i);
     }
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index f8034b04bf..cf3d94c537 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -34,9 +34,10 @@ Stream::Stream(Core::Timing::CoreTiming& core_timing_, u32 sample_rate_, Format
                ReleaseCallback&& release_callback_, SinkStream& sink_stream_, std::string&& name_)
     : sample_rate{sample_rate_}, format{format_}, release_callback{std::move(release_callback_)},
       sink_stream{sink_stream_}, core_timing{core_timing_}, name{std::move(name_)} {
-    release_event =
-        Core::Timing::CreateEvent(name, [this](std::uintptr_t, std::chrono::nanoseconds ns_late) {
+    release_event = Core::Timing::CreateEvent(
+        name, [this](std::uintptr_t, s64 time, std::chrono::nanoseconds ns_late) {
             ReleaseActiveBuffer(ns_late);
+            return std::nullopt;
         });
 }
 
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 07b8e356b9..5425637f5b 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -22,10 +22,11 @@ std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callbac
 }
 
 struct CoreTiming::Event {
-    u64 time;
+    s64 time;
     u64 fifo_order;
     std::uintptr_t user_data;
     std::weak_ptr<EventType> type;
+    s64 reschedule_time;
 
     // Sort by time, unless the times are the same, in which case sort by
     // the order added to the queue
@@ -58,7 +59,8 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
     event_fifo_id = 0;
     shutting_down = false;
     ticks = 0;
-    const auto empty_timed_callback = [](std::uintptr_t, std::chrono::nanoseconds) {};
+    const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds)
+        -> std::optional<std::chrono::nanoseconds> { return std::nullopt; };
     ev_lost = CreateEvent("_lost_event", empty_timed_callback);
     if (is_multicore) {
         worker_threads.emplace_back(ThreadEntry, std::ref(*this), 0);
@@ -76,6 +78,7 @@ void CoreTiming::Shutdown() {
         thread.join();
     }
     worker_threads.clear();
+    pause_callbacks.clear();
     ClearPendingEvents();
     has_started = false;
 }
@@ -93,6 +96,14 @@ void CoreTiming::Pause(bool is_paused_) {
         }
     }
     paused_state.store(is_paused_, std::memory_order_relaxed);
+
+    if (!is_paused_) {
+        pause_end_time = GetGlobalTimeNs().count();
+    }
+
+    for (auto& cb : pause_callbacks) {
+        cb(is_paused_);
+    }
 }
 
 void CoreTiming::SyncPause(bool is_paused_) {
@@ -116,6 +127,14 @@ void CoreTiming::SyncPause(bool is_paused_) {
             wait_signal_cv.wait(main_lock, [this] { return pause_count == 0; });
         }
     }
+
+    if (!is_paused_) {
+        pause_end_time = GetGlobalTimeNs().count();
+    }
+
+    for (auto& cb : pause_callbacks) {
+        cb(is_paused_);
+    }
 }
 
 bool CoreTiming::IsRunning() const {
@@ -129,12 +148,30 @@ bool CoreTiming::HasPendingEvents() const {
 
 void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
                                const std::shared_ptr<EventType>& event_type,
-                               std::uintptr_t user_data) {
+                               std::uintptr_t user_data, bool absolute_time) {
 
     std::unique_lock main_lock(event_mutex);
-    const u64 timeout = static_cast<u64>((GetGlobalTimeNs() + ns_into_future).count());
+    const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future};
 
-    event_queue.emplace_back(Event{timeout, event_fifo_id++, user_data, event_type});
+    event_queue.emplace_back(Event{next_time.count(), event_fifo_id++, user_data, event_type, 0});
+    pending_events.fetch_add(1, std::memory_order_relaxed);
+
+    std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
+
+    if (is_multicore) {
+        event_cv.notify_one();
+    }
+}
+
+void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
+                                      std::chrono::nanoseconds resched_time,
+                                      const std::shared_ptr<EventType>& event_type,
+                                      std::uintptr_t user_data, bool absolute_time) {
+    std::unique_lock main_lock(event_mutex);
+    const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time};
+
+    event_queue.emplace_back(
+        Event{next_time.count(), event_fifo_id++, user_data, event_type, resched_time.count()});
     pending_events.fetch_add(1, std::memory_order_relaxed);
 
     std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
@@ -213,6 +250,11 @@ void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
     }
 }
 
+void CoreTiming::RegisterPauseCallback(PauseCallback&& callback) {
+    std::unique_lock main_lock(event_mutex);
+    pause_callbacks.emplace_back(std::move(callback));
+}
+
 std::optional<s64> CoreTiming::Advance() {
     global_timer = GetGlobalTimeNs().count();
 
@@ -223,14 +265,31 @@ std::optional<s64> CoreTiming::Advance() {
         event_queue.pop_back();
 
         if (const auto event_type{evt.type.lock()}) {
-
             event_mutex.unlock();
 
-            const s64 delay = static_cast<s64>(GetGlobalTimeNs().count() - evt.time);
-            event_type->callback(evt.user_data, std::chrono::nanoseconds{delay});
+            const auto new_schedule_time{event_type->callback(
+                evt.user_data, evt.time,
+                std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt.time})};
 
             event_mutex.lock();
             pending_events.fetch_sub(1, std::memory_order_relaxed);
+
+            if (evt.reschedule_time != 0) {
+                // If this event was scheduled into a pause, its time now is going to be way behind.
+                // Re-set this event to continue from the end of the pause.
+                auto next_time{evt.time + evt.reschedule_time};
+                if (evt.time < pause_end_time) {
+                    next_time = pause_end_time + evt.reschedule_time;
+                }
+
+                const auto next_schedule_time{new_schedule_time.has_value()
+                                                  ? new_schedule_time.value().count()
+                                                  : evt.reschedule_time};
+                event_queue.emplace_back(
+                    Event{next_time, event_fifo_id++, evt.user_data, evt.type, next_schedule_time});
+                pending_events.fetch_add(1, std::memory_order_relaxed);
+                std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
+            }
         }
 
         global_timer = GetGlobalTimeNs().count();
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index c52bffb3b6..09b6ed81a4 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -20,8 +20,9 @@
 namespace Core::Timing {
 
 /// A callback that may be scheduled for a particular core timing event.
-using TimedCallback =
-    std::function<void(std::uintptr_t user_data, std::chrono::nanoseconds ns_late)>;
+using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>(
+    std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)>;
+using PauseCallback = std::function<void(bool paused)>;
 
 /// Contains the characteristics of a particular event.
 struct EventType {
@@ -93,7 +94,15 @@ public:
 
     /// Schedules an event in core timing
     void ScheduleEvent(std::chrono::nanoseconds ns_into_future,
-                       const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0);
+                       const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0,
+                       bool absolute_time = false);
+
+    /// Schedules an event which will automatically re-schedule itself with the given time, until
+    /// unscheduled
+    void ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
+                              std::chrono::nanoseconds resched_time,
+                              const std::shared_ptr<EventType>& event_type,
+                              std::uintptr_t user_data = 0, bool absolute_time = false);
 
     void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data);
 
@@ -125,6 +134,9 @@ public:
     /// Checks for events manually and returns time in nanoseconds for next event, threadsafe.
     std::optional<s64> Advance();
 
+    /// Register a callback function to be called when coretiming pauses.
+    void RegisterPauseCallback(PauseCallback&& callback);
+
 private:
     struct Event;
 
@@ -136,7 +148,7 @@ private:
 
     std::unique_ptr<Common::WallClock> clock;
 
-    u64 global_timer = 0;
+    s64 global_timer = 0;
 
     // The queue is a min-heap using std::make_heap/push_heap/pop_heap.
     // We don't use std::priority_queue because we need to be able to serialize, unserialize and
@@ -162,10 +174,13 @@ private:
     bool shutting_down{};
     bool is_multicore{};
     size_t pause_count{};
+    s64 pause_end_time{};
 
     /// Cycle timing
     u64 ticks{};
     s64 downcount{};
+
+    std::vector<PauseCallback> pause_callbacks{};
 };
 
 /// Creates a core timing event with the given name and callback.
diff --git a/src/core/hardware_interrupt_manager.cpp b/src/core/hardware_interrupt_manager.cpp
index d2d968a766..d08cc33159 100644
--- a/src/core/hardware_interrupt_manager.cpp
+++ b/src/core/hardware_interrupt_manager.cpp
@@ -11,11 +11,14 @@ namespace Core::Hardware {
 
 InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) {
     gpu_interrupt_event = Core::Timing::CreateEvent(
-        "GPUInterrupt", [this](std::uintptr_t message, std::chrono::nanoseconds) {
+        "GPUInterrupt",
+        [this](std::uintptr_t message, u64 time,
+               std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
             auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv");
             const u32 syncpt = static_cast<u32>(message >> 32);
             const u32 value = static_cast<u32>(message);
             nvdrv->SignalGPUInterruptSyncpt(syncpt, value);
+            return std::nullopt;
         });
 }
 
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 0009193be4..ee91a9b685 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -234,17 +234,19 @@ struct KernelCore::Impl {
 
     void InitializePreemption(KernelCore& kernel) {
         preemption_event = Core::Timing::CreateEvent(
-            "PreemptionCallback", [this, &kernel](std::uintptr_t, std::chrono::nanoseconds) {
+            "PreemptionCallback",
+            [this, &kernel](std::uintptr_t, s64 time,
+                            std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
                 {
                     KScopedSchedulerLock lock(kernel);
                     global_scheduler_context->PreemptThreads();
                 }
-                const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)};
-                system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
+                return std::nullopt;
             });
 
         const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)};
-        system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
+        system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), time_interval,
+                                                 preemption_event);
     }
 
     void InitializeShutdownThreads() {
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp
index 2724c3782a..5ee72c432a 100644
--- a/src/core/hle/kernel/time_manager.cpp
+++ b/src/core/hle/kernel/time_manager.cpp
@@ -11,15 +11,17 @@
 namespace Kernel {
 
 TimeManager::TimeManager(Core::System& system_) : system{system_} {
-    time_manager_event_type =
-        Core::Timing::CreateEvent("Kernel::TimeManagerCallback",
-                                  [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) {
-                                      KThread* thread = reinterpret_cast<KThread*>(thread_handle);
-                                      {
-                                          KScopedSchedulerLock sl(system.Kernel());
-                                          thread->OnTimer();
-                                      }
-                                  });
+    time_manager_event_type = Core::Timing::CreateEvent(
+        "Kernel::TimeManagerCallback",
+        [this](std::uintptr_t thread_handle, s64 time,
+               std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
+            KThread* thread = reinterpret_cast<KThread*>(thread_handle);
+            {
+                KScopedSchedulerLock sl(system.Kernel());
+                thread->OnTimer();
+            }
+            return std::nullopt;
+        });
 }
 
 void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) {
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 78efffc50a..88fcd53ec3 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -74,26 +74,35 @@ IAppletResource::IAppletResource(Core::System& system_,
     // Register update callbacks
     pad_update_event = Core::Timing::CreateEvent(
         "HID::UpdatePadCallback",
-        [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+        [this](std::uintptr_t user_data, s64 time,
+               std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
             const auto guard = LockService();
             UpdateControllers(user_data, ns_late);
+            return std::nullopt;
         });
     mouse_keyboard_update_event = Core::Timing::CreateEvent(
         "HID::UpdateMouseKeyboardCallback",
-        [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+        [this](std::uintptr_t user_data, s64 time,
+               std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
             const auto guard = LockService();
             UpdateMouseKeyboard(user_data, ns_late);
+            return std::nullopt;
         });
     motion_update_event = Core::Timing::CreateEvent(
         "HID::UpdateMotionCallback",
-        [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+        [this](std::uintptr_t user_data, s64 time,
+               std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
             const auto guard = LockService();
             UpdateMotion(user_data, ns_late);
+            return std::nullopt;
         });
 
-    system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event);
-    system.CoreTiming().ScheduleEvent(mouse_keyboard_update_ns, mouse_keyboard_update_event);
-    system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event);
+    system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), pad_update_ns,
+                                             pad_update_event);
+    system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), mouse_keyboard_update_ns,
+                                             mouse_keyboard_update_event);
+    system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), motion_update_ns,
+                                             motion_update_event);
 
     system.HIDCore().ReloadInputDevices();
 }
@@ -135,13 +144,6 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
         }
         controller->OnUpdate(core_timing);
     }
-
-    // If ns_late is higher than the update rate ignore the delay
-    if (ns_late > pad_update_ns) {
-        ns_late = {};
-    }
-
-    core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event);
 }
 
 void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,
@@ -150,26 +152,12 @@ void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,
 
     controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing);
     controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing);
-
-    // If ns_late is higher than the update rate ignore the delay
-    if (ns_late > mouse_keyboard_update_ns) {
-        ns_late = {};
-    }
-
-    core_timing.ScheduleEvent(mouse_keyboard_update_ns - ns_late, mouse_keyboard_update_event);
 }
 
 void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
     auto& core_timing = system.CoreTiming();
 
     controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing);
-
-    // If ns_late is higher than the update rate ignore the delay
-    if (ns_late > motion_update_ns) {
-        ns_late = {};
-    }
-
-    core_timing.ScheduleEvent(motion_update_ns - ns_late, motion_update_event);
 }
 
 class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp
index fa6153b4c8..5e20e6830b 100644
--- a/src/core/hle/service/hid/hidbus.cpp
+++ b/src/core/hle/service/hid/hidbus.cpp
@@ -50,12 +50,15 @@ HidBus::HidBus(Core::System& system_)
     // Register update callbacks
     hidbus_update_event = Core::Timing::CreateEvent(
         "Hidbus::UpdateCallback",
-        [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+        [this](std::uintptr_t user_data, s64 time,
+               std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
             const auto guard = LockService();
             UpdateHidbus(user_data, ns_late);
+            return std::nullopt;
         });
 
-    system_.CoreTiming().ScheduleEvent(hidbus_update_ns, hidbus_update_event);
+    system_.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), hidbus_update_ns,
+                                              hidbus_update_event);
 }
 
 HidBus::~HidBus() {
@@ -63,8 +66,6 @@ HidBus::~HidBus() {
 }
 
 void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
-    auto& core_timing = system.CoreTiming();
-
     if (is_hidbus_enabled) {
         for (std::size_t i = 0; i < devices.size(); ++i) {
             if (!devices[i].is_device_initializated) {
@@ -82,13 +83,6 @@ void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_
                         sizeof(HidbusStatusManagerEntry));
         }
     }
-
-    // If ns_late is higher than the update rate ignore the delay
-    if (ns_late > hidbus_update_ns) {
-        ns_late = {};
-    }
-
-    core_timing.ScheduleEvent(hidbus_update_ns - ns_late, hidbus_update_event);
 }
 
 std::optional<std::size_t> HidBus::GetDeviceIndexFromHandle(BusHandle handle) const {
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 2b2985a2d4..600b19b3f8 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -67,21 +67,20 @@ NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_dr
 
     // Schedule the screen composition events
     composition_event = Core::Timing::CreateEvent(
-        "ScreenComposition", [this](std::uintptr_t, std::chrono::nanoseconds ns_late) {
+        "ScreenComposition",
+        [this](std::uintptr_t, s64 time,
+               std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
             const auto lock_guard = Lock();
             Compose();
 
-            const auto ticks = std::chrono::nanoseconds{GetNextTicks()};
-            const auto ticks_delta = ticks - ns_late;
-            const auto future_ns = std::max(std::chrono::nanoseconds::zero(), ticks_delta);
-
-            this->system.CoreTiming().ScheduleEvent(future_ns, composition_event);
+            return std::chrono::nanoseconds(GetNextTicks()) - ns_late;
         });
 
     if (system.IsMulticore()) {
         vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); });
     } else {
-        system.CoreTiming().ScheduleEvent(frame_ns, composition_event);
+        system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), frame_ns,
+                                                 composition_event);
     }
 }
 
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index 5f71f0ff51..09a02d2ac7 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -184,10 +184,12 @@ CheatEngine::~CheatEngine() {
 void CheatEngine::Initialize() {
     event = Core::Timing::CreateEvent(
         "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id),
-        [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+        [this](std::uintptr_t user_data, s64 time,
+               std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
             FrameCallback(user_data, ns_late);
+            return std::nullopt;
         });
-    core_timing.ScheduleEvent(CHEAT_ENGINE_NS, event);
+    core_timing.ScheduleLoopingEvent(std::chrono::nanoseconds(0), CHEAT_ENGINE_NS, event);
 
     metadata.process_id = system.CurrentProcess()->GetProcessID();
     metadata.title_id = system.GetCurrentProcessProgramID();
@@ -237,8 +239,6 @@ void CheatEngine::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late
     MICROPROFILE_SCOPE(Cheat_Engine);
 
     vm.Execute(metadata);
-
-    core_timing.ScheduleEvent(CHEAT_ENGINE_NS - ns_late, event);
 }
 
 } // namespace Core::Memory
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp
index 5cc99fbe42..98ebbbf329 100644
--- a/src/core/tools/freezer.cpp
+++ b/src/core/tools/freezer.cpp
@@ -53,8 +53,10 @@ Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& m
     : core_timing{core_timing_}, memory{memory_} {
     event = Core::Timing::CreateEvent(
         "MemoryFreezer::FrameCallback",
-        [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+        [this](std::uintptr_t user_data, s64 time,
+               std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
             FrameCallback(user_data, ns_late);
+            return std::nullopt;
         });
     core_timing.ScheduleEvent(memory_freezer_ns, event);
 }
diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp
index e687416a81..894975e6f6 100644
--- a/src/tests/core/core_timing.cpp
+++ b/src/tests/core/core_timing.cpp
@@ -9,6 +9,7 @@
 #include <cstdlib>
 #include <memory>
 #include <mutex>
+#include <optional>
 #include <string>
 
 #include "core/core.h"
@@ -25,13 +26,15 @@ u64 expected_callback = 0;
 std::mutex control_mutex;
 
 template <unsigned int IDX>
-void HostCallbackTemplate(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+std::optional<std::chrono::nanoseconds> HostCallbackTemplate(std::uintptr_t user_data, s64 time,
+                                                             std::chrono::nanoseconds ns_late) {
     std::unique_lock<std::mutex> lk(control_mutex);
     static_assert(IDX < CB_IDS.size(), "IDX out of range");
     callbacks_ran_flags.set(IDX);
     REQUIRE(CB_IDS[IDX] == user_data);
     delays[IDX] = ns_late.count();
     ++expected_callback;
+    return std::nullopt;
 }
 
 struct ScopeInit final {