From f95803664be37d8be515433e0e734f4124896478 Mon Sep 17 00:00:00 2001
From: Nenkai <Nenkai@users.noreply.github.com>
Date: Fri, 27 Dec 2024 19:33:45 +0100
Subject: [PATCH 1/6] equeue: sceGnmGetEqEventType/sceKernelGetEventData impl
 (#1839)

---
 src/core/libraries/gnmdriver/gnmdriver.cpp | 37 +++++++++++++++-------
 src/core/libraries/gnmdriver/gnmdriver.h   |  2 +-
 src/core/libraries/kernel/equeue.cpp       | 23 ++++++++++----
 src/core/libraries/kernel/equeue.h         | 11 +++++--
 4 files changed, 51 insertions(+), 22 deletions(-)

diff --git a/src/core/libraries/gnmdriver/gnmdriver.cpp b/src/core/libraries/gnmdriver/gnmdriver.cpp
index 1a6007bf8f0..566f8ce1f04 100644
--- a/src/core/libraries/gnmdriver/gnmdriver.cpp
+++ b/src/core/libraries/gnmdriver/gnmdriver.cpp
@@ -29,7 +29,7 @@ namespace Libraries::GnmDriver {
 
 using namespace AmdGpu;
 
-enum GnmEventIdents : u64 {
+enum GnmEventType : u64 {
     Compute0RelMem = 0x00,
     Compute1RelMem = 0x01,
     Compute2RelMem = 0x02,
@@ -337,6 +337,12 @@ static inline u32* ClearContextState(u32* cmdbuf) {
     return cmdbuf + ClearStateSequence.size();
 }
 
+static inline bool IsValidEventType(Platform::InterruptId id) {
+    return (static_cast<u32>(id) >= static_cast<u32>(Platform::InterruptId::Compute0RelMem) &&
+            static_cast<u32>(id) <= static_cast<u32>(Platform::InterruptId::Compute6RelMem)) ||
+           static_cast<u32>(id) == static_cast<u32>(Platform::InterruptId::GfxEop);
+}
+
 s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) {
     LOG_TRACE(Lib_GnmDriver, "called");
 
@@ -347,8 +353,7 @@ s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) {
     EqueueEvent kernel_event{};
     kernel_event.event.ident = id;
     kernel_event.event.filter = SceKernelEvent::Filter::GraphicsCore;
-    // The library only sets EV_ADD but it is suspected the kernel driver forces EV_CLEAR
-    kernel_event.event.flags = SceKernelEvent::Flags::Clear;
+    kernel_event.event.flags = SceKernelEvent::Flags::Add;
     kernel_event.event.fflags = 0;
     kernel_event.event.data = id;
     kernel_event.event.udata = udata;
@@ -357,11 +362,15 @@ s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) {
     Platform::IrqC::Instance()->Register(
         static_cast<Platform::InterruptId>(id),
         [=](Platform::InterruptId irq) {
-            ASSERT_MSG(irq == static_cast<Platform::InterruptId>(id),
-                       "An unexpected IRQ occured"); // We need to convert IRQ# to event id and do
-                                                     // proper filtering in trigger function
-            eq->TriggerEvent(static_cast<GnmEventIdents>(id), SceKernelEvent::Filter::GraphicsCore,
-                             nullptr);
+            ASSERT_MSG(irq == static_cast<Platform::InterruptId>(id), "An unexpected IRQ occured");
+
+            // We need to convert IRQ# to event id
+            if (!IsValidEventType(irq))
+                return;
+
+            // Event data is expected to be an event type as per sceGnmGetEqEventType.
+            eq->TriggerEvent(static_cast<GnmEventType>(id), SceKernelEvent::Filter::GraphicsCore,
+                             reinterpret_cast<void*>(id));
         },
         eq);
     return ORBIS_OK;
@@ -476,7 +485,7 @@ s32 PS4_SYSV_ABI sceGnmDeleteEqEvent(SceKernelEqueue eq, u64 id) {
         return ORBIS_KERNEL_ERROR_EBADF;
     }
 
-    eq->RemoveEvent(id);
+    eq->RemoveEvent(id, SceKernelEvent::Filter::GraphicsCore);
 
     Platform::IrqC::Instance()->Unregister(static_cast<Platform::InterruptId>(id), eq);
     return ORBIS_OK;
@@ -1000,9 +1009,13 @@ int PS4_SYSV_ABI sceGnmGetDebugTimestamp() {
     return ORBIS_OK;
 }
 
-int PS4_SYSV_ABI sceGnmGetEqEventType() {
-    LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
-    return ORBIS_OK;
+int PS4_SYSV_ABI sceGnmGetEqEventType(const SceKernelEvent* ev) {
+    LOG_TRACE(Lib_GnmDriver, "called");
+
+    auto data = sceKernelGetEventData(ev);
+    ASSERT(static_cast<GnmEventType>(data) == GnmEventType::GfxEop);
+
+    return data;
 }
 
 int PS4_SYSV_ABI sceGnmGetEqTimeStamp() {
diff --git a/src/core/libraries/gnmdriver/gnmdriver.h b/src/core/libraries/gnmdriver/gnmdriver.h
index 017dbe3ad3d..d15483323eb 100644
--- a/src/core/libraries/gnmdriver/gnmdriver.h
+++ b/src/core/libraries/gnmdriver/gnmdriver.h
@@ -85,7 +85,7 @@ int PS4_SYSV_ABI sceGnmGetCoredumpMode();
 int PS4_SYSV_ABI sceGnmGetCoredumpProtectionFaultTimestamp();
 int PS4_SYSV_ABI sceGnmGetDbgGcHandle();
 int PS4_SYSV_ABI sceGnmGetDebugTimestamp();
-int PS4_SYSV_ABI sceGnmGetEqEventType();
+int PS4_SYSV_ABI sceGnmGetEqEventType(const SceKernelEvent* ev);
 int PS4_SYSV_ABI sceGnmGetEqTimeStamp();
 int PS4_SYSV_ABI sceGnmGetGpuBlockStatus();
 u32 PS4_SYSV_ABI sceGnmGetGpuCoreClockFrequency();
diff --git a/src/core/libraries/kernel/equeue.cpp b/src/core/libraries/kernel/equeue.cpp
index 42a8eed894c..3ae77e46bd4 100644
--- a/src/core/libraries/kernel/equeue.cpp
+++ b/src/core/libraries/kernel/equeue.cpp
@@ -12,6 +12,8 @@
 
 namespace Libraries::Kernel {
 
+// Events are uniquely identified by id and filter.
+
 bool EqueueInternal::AddEvent(EqueueEvent& event) {
     std::scoped_lock lock{m_mutex};
 
@@ -27,12 +29,13 @@ bool EqueueInternal::AddEvent(EqueueEvent& event) {
     return true;
 }
 
-bool EqueueInternal::RemoveEvent(u64 id) {
+bool EqueueInternal::RemoveEvent(u64 id, s16 filter) {
     bool has_found = false;
     std::scoped_lock lock{m_mutex};
 
-    const auto& it =
-        std::ranges::find_if(m_events, [id](auto& ev) { return ev.event.ident == id; });
+    const auto& it = std::ranges::find_if(m_events, [id, filter](auto& ev) {
+        return ev.event.ident == id && ev.event.filter == filter;
+    });
     if (it != m_events.cend()) {
         m_events.erase(it);
         has_found = true;
@@ -68,7 +71,7 @@ int EqueueInternal::WaitForEvents(SceKernelEvent* ev, int num, u32 micros) {
 
     if (ev->flags & SceKernelEvent::Flags::OneShot) {
         for (auto ev_id = 0u; ev_id < count; ++ev_id) {
-            RemoveEvent(ev->ident);
+            RemoveEvent(ev->ident, ev->filter);
         }
     }
 
@@ -94,8 +97,11 @@ int EqueueInternal::GetTriggeredEvents(SceKernelEvent* ev, int num) {
     int count = 0;
     for (auto& event : m_events) {
         if (event.IsTriggered()) {
+            // Event should not trigger again
+            event.ResetTriggerState();
+
             if (event.event.flags & SceKernelEvent::Flags::Clear) {
-                event.Reset();
+                event.Clear();
             }
             ev[count++] = event.event;
             if (count == num) {
@@ -334,7 +340,7 @@ int PS4_SYSV_ABI sceKernelDeleteUserEvent(SceKernelEqueue eq, int id) {
         return ORBIS_KERNEL_ERROR_EBADF;
     }
 
-    if (!eq->RemoveEvent(id)) {
+    if (!eq->RemoveEvent(id, SceKernelEvent::Filter::User)) {
         return ORBIS_KERNEL_ERROR_ENOENT;
     }
     return ORBIS_OK;
@@ -344,6 +350,10 @@ s16 PS4_SYSV_ABI sceKernelGetEventFilter(const SceKernelEvent* ev) {
     return ev->filter;
 }
 
+u64 PS4_SYSV_ABI sceKernelGetEventData(const SceKernelEvent* ev) {
+    return ev->data;
+}
+
 void RegisterEventQueue(Core::Loader::SymbolsResolver* sym) {
     LIB_FUNCTION("D0OdFMjp46I", "libkernel", 1, "libkernel", 1, 1, sceKernelCreateEqueue);
     LIB_FUNCTION("jpFjmgAC5AE", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteEqueue);
@@ -356,6 +366,7 @@ void RegisterEventQueue(Core::Loader::SymbolsResolver* sym) {
     LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent);
     LIB_FUNCTION("mJ7aghmgvfc", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventId);
     LIB_FUNCTION("23CPPI1tyBY", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventFilter);
+    LIB_FUNCTION("kwGyyjohI50", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventData);
 }
 
 } // namespace Libraries::Kernel
diff --git a/src/core/libraries/kernel/equeue.h b/src/core/libraries/kernel/equeue.h
index 5a13bdecde2..f8759137c24 100644
--- a/src/core/libraries/kernel/equeue.h
+++ b/src/core/libraries/kernel/equeue.h
@@ -66,8 +66,11 @@ struct EqueueEvent {
     std::chrono::steady_clock::time_point time_added;
     std::unique_ptr<boost::asio::steady_timer> timer;
 
-    void Reset() {
+    void ResetTriggerState() {
         is_triggered = false;
+    }
+
+    void Clear() {
         event.fflags = 0;
         event.data = 0;
     }
@@ -83,7 +86,7 @@ struct EqueueEvent {
     }
 
     bool operator==(const EqueueEvent& ev) const {
-        return ev.event.ident == event.ident;
+        return ev.event.ident == event.ident && ev.event.filter == event.filter;
     }
 
 private:
@@ -99,7 +102,7 @@ class EqueueInternal {
     }
 
     bool AddEvent(EqueueEvent& event);
-    bool RemoveEvent(u64 id);
+    bool RemoveEvent(u64 id, s16 filter);
     int WaitForEvents(SceKernelEvent* ev, int num, u32 micros);
     bool TriggerEvent(u64 ident, s16 filter, void* trigger_data);
     int GetTriggeredEvents(SceKernelEvent* ev, int num);
@@ -122,6 +125,8 @@ class EqueueInternal {
 using SceKernelUseconds = u32;
 using SceKernelEqueue = EqueueInternal*;
 
+u64 PS4_SYSV_ABI sceKernelGetEventData(const SceKernelEvent* ev);
+
 void RegisterEventQueue(Core::Loader::SymbolsResolver* sym);
 
 } // namespace Libraries::Kernel

From 333f35ef2565fd24d93194893e04bd21fab32b20 Mon Sep 17 00:00:00 2001
From: squidbus <175574877+squidbus@users.noreply.github.com>
Date: Fri, 27 Dec 2024 11:04:49 -0800
Subject: [PATCH 2/6] audio: Implement cubeb audio out backend. (#1895)

* audio: Implement cubeb audio out backend.

* cubeb_audio: Add some additional safety checks.

* cubeb_audio: Add debug logging callback.

* audioout: Refactor backend ports into class.

* pthread: Bump minimum stack size to fix cubeb crash.

* cubeb_audio: Replace output yield loop with condvar.

* common: Rename ring_buffer_base to RingBuffer.
---
 .gitmodules                                   |   4 +
 CMakeLists.txt                                |   9 +-
 LICENSES/ISC.txt                              |   7 +
 externals/CMakeLists.txt                      |  10 +
 externals/cubeb                               |   1 +
 src/common/config.cpp                         |  17 +
 src/common/config.h                           |   2 +
 src/common/ringbuffer.h                       | 374 ++++++++++++++++++
 src/core/libraries/audio/audioout.cpp         |  59 ++-
 src/core/libraries/audio/audioout.h           |  24 +-
 src/core/libraries/audio/audioout_backend.h   |  33 +-
 src/core/libraries/audio/cubeb_audio.cpp      | 158 ++++++++
 src/core/libraries/audio/sdl_audio.cpp        |  68 ++--
 src/core/libraries/audio/sdl_audio.h          |  18 -
 src/core/libraries/kernel/threads/pthread.cpp |   4 +-
 src/emulator.cpp                              |   2 +-
 src/qt_gui/settings_dialog.cpp                |   6 +
 src/qt_gui/settings_dialog.ui                 |  23 ++
 18 files changed, 731 insertions(+), 88 deletions(-)
 create mode 100644 LICENSES/ISC.txt
 create mode 160000 externals/cubeb
 create mode 100644 src/common/ringbuffer.h
 create mode 100644 src/core/libraries/audio/cubeb_audio.cpp
 delete mode 100644 src/core/libraries/audio/sdl_audio.h

diff --git a/.gitmodules b/.gitmodules
index 3d0d21c5b6d..1c05ba6f33b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -119,3 +119,7 @@
 	path = externals/MoltenVK/cereal
 	url = https://github.com/USCiLab/cereal
 	shallow = true
+[submodule "externals/cubeb"]
+	path = externals/cubeb
+	url = https://github.com/mozilla/cubeb
+	shallow = true
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 30a0482788d..5c236660153 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -127,6 +127,7 @@ find_package(xxHash 0.8.2 MODULE)
 find_package(ZLIB 1.3 MODULE)
 find_package(Zydis 5.0.0 CONFIG)
 find_package(pugixml 1.14 CONFIG)
+find_package(cubeb CONFIG)
 
 if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR NOT MSVC)
     find_package(cryptopp 8.9.0 MODULE)
@@ -198,9 +199,10 @@ set(AUDIO_LIB src/core/libraries/audio/audioin.cpp
               src/core/libraries/audio/audioin.h
               src/core/libraries/audio/audioout.cpp
               src/core/libraries/audio/audioout.h
-              src/core/libraries/audio/sdl_audio.cpp
-              src/core/libraries/audio/sdl_audio.h
+              src/core/libraries/audio/audioout_backend.h
               src/core/libraries/audio/audioout_error.h
+              src/core/libraries/audio/cubeb_audio.cpp
+              src/core/libraries/audio/sdl_audio.cpp
               src/core/libraries/ngs2/ngs2.cpp
               src/core/libraries/ngs2/ngs2.h
 )
@@ -493,6 +495,7 @@ set(COMMON src/common/logging/backend.cpp
            src/common/polyfill_thread.h
            src/common/rdtsc.cpp
            src/common/rdtsc.h
+           src/common/ringbuffer.h
            src/common/signal_context.h
            src/common/signal_context.cpp
            src/common/singleton.h
@@ -884,7 +887,7 @@ endif()
 create_target_directory_groups(shadps4)
 
 target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn half::half ZLIB::ZLIB PNG::PNG)
-target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 pugixml::pugixml stb::headers)
+target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 pugixml::pugixml stb::headers cubeb::cubeb)
 
 target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h")
 target_compile_definitions(Dear_ImGui PRIVATE IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/src/imgui/imgui_config.h")
diff --git a/LICENSES/ISC.txt b/LICENSES/ISC.txt
new file mode 100644
index 00000000000..b9bcfa3a4a0
--- /dev/null
+++ b/LICENSES/ISC.txt
@@ -0,0 +1,7 @@
+ISC License
+
+<copyright notice>
+
+Permission to use, copy, modify, and /or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 4350948b7e2..8bdf089f877 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -228,6 +228,16 @@ if (NOT TARGET stb::headers)
     add_library(stb::headers ALIAS stb)
 endif()
 
+# cubeb
+if (NOT TARGET cubeb::cubeb)
+    option(BUILD_TESTS "" OFF)
+    option(BUILD_TOOLS "" OFF)
+    option(BUNDLE_SPEEX "" ON)
+    option(USE_SANITIZERS "" OFF)
+    add_subdirectory(cubeb)
+    add_library(cubeb::cubeb ALIAS cubeb)
+endif()
+
 # Apple-only dependencies
 if (APPLE)
     # date
diff --git a/externals/cubeb b/externals/cubeb
new file mode 160000
index 00000000000..9a9d034c518
--- /dev/null
+++ b/externals/cubeb
@@ -0,0 +1 @@
+Subproject commit 9a9d034c51859a045a34f201334f612c51e6c19d
diff --git a/src/common/config.cpp b/src/common/config.cpp
index deef0fa88b8..93627d8c903 100644
--- a/src/common/config.cpp
+++ b/src/common/config.cpp
@@ -67,6 +67,7 @@ static int cursorHideTimeout = 5; // 5 seconds (default)
 static bool separateupdatefolder = false;
 static bool compatibilityData = false;
 static bool checkCompatibilityOnStartup = false;
+static std::string audioBackend = "cubeb";
 
 // Gui
 std::vector<std::filesystem::path> settings_install_dirs = {};
@@ -239,6 +240,10 @@ bool getCheckCompatibilityOnStartup() {
     return checkCompatibilityOnStartup;
 }
 
+std::string getAudioBackend() {
+    return audioBackend;
+}
+
 void setGpuId(s32 selectedGpuId) {
     gpuId = selectedGpuId;
 }
@@ -371,6 +376,10 @@ void setCheckCompatibilityOnStartup(bool use) {
     checkCompatibilityOnStartup = use;
 }
 
+void setAudioBackend(std::string backend) {
+    audioBackend = backend;
+}
+
 void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) {
     main_window_geometry_x = x;
     main_window_geometry_y = y;
@@ -611,6 +620,12 @@ void load(const std::filesystem::path& path) {
         vkCrashDiagnostic = toml::find_or<bool>(vk, "crashDiagnostic", false);
     }
 
+    if (data.contains("Audio")) {
+        const toml::value& audio = data.at("Audio");
+
+        audioBackend = toml::find_or<std::string>(audio, "backend", "cubeb");
+    }
+
     if (data.contains("Debug")) {
         const toml::value& debug = data.at("Debug");
 
@@ -709,6 +724,7 @@ void save(const std::filesystem::path& path) {
     data["Vulkan"]["rdocEnable"] = rdocEnable;
     data["Vulkan"]["rdocMarkersEnable"] = vkMarkers;
     data["Vulkan"]["crashDiagnostic"] = vkCrashDiagnostic;
+    data["Audio"]["backend"] = audioBackend;
     data["Debug"]["DebugDump"] = isDebugDump;
     data["Debug"]["CollectShader"] = isShaderDebug;
 
@@ -812,6 +828,7 @@ void setDefaultValues() {
     separateupdatefolder = false;
     compatibilityData = false;
     checkCompatibilityOnStartup = false;
+    audioBackend = "cubeb";
 }
 
 } // namespace Config
diff --git a/src/common/config.h b/src/common/config.h
index 701aadb12c1..43ef5024bdd 100644
--- a/src/common/config.h
+++ b/src/common/config.h
@@ -24,6 +24,7 @@ bool getEnableDiscordRPC();
 bool getSeparateUpdateEnabled();
 bool getCompatibilityEnabled();
 bool getCheckCompatibilityOnStartup();
+std::string getAudioBackend();
 
 std::string getLogFilter();
 std::string getLogType();
@@ -75,6 +76,7 @@ void setSeparateUpdateEnabled(bool use);
 void setGameInstallDirs(const std::vector<std::filesystem::path>& settings_install_dirs_config);
 void setCompatibilityEnabled(bool use);
 void setCheckCompatibilityOnStartup(bool use);
+void setAudioBackend(std::string backend);
 
 void setCursorState(s16 cursorState);
 void setCursorHideTimeout(int newcursorHideTimeout);
diff --git a/src/common/ringbuffer.h b/src/common/ringbuffer.h
new file mode 100644
index 00000000000..6a71c2888f3
--- /dev/null
+++ b/src/common/ringbuffer.h
@@ -0,0 +1,374 @@
+// SPDX-FileCopyrightText: Copyright 2016 Mozilla Foundation
+// SPDX-License-Identifier: ISC
+
+#pragma once
+
+#include <algorithm>
+#include <atomic>
+#include <cstdint>
+#include <memory>
+#include <thread>
+#include "common/assert.h"
+
+/**
+ * Single producer single consumer lock-free and wait-free ring buffer.
+ *
+ * This data structure allows producing data from one thread, and consuming it
+ * on another thread, safely and without explicit synchronization. If used on
+ * two threads, this data structure uses atomics for thread safety. It is
+ * possible to disable the use of atomics at compile time and only use this data
+ * structure on one thread.
+ *
+ * The role for the producer and the consumer must be constant, i.e., the
+ * producer should always be on one thread and the consumer should always be on
+ * another thread.
+ *
+ * Some words about the inner workings of this class:
+ * - Capacity is fixed. Only one allocation is performed, in the constructor.
+ *   When reading and writing, the return value of the method allows checking if
+ *   the ring buffer is empty or full.
+ * - We always keep the read index at least one element ahead of the write
+ *   index, so we can distinguish between an empty and a full ring buffer: an
+ *   empty ring buffer is when the write index is at the same position as the
+ *   read index. A full buffer is when the write index is exactly one position
+ *   before the read index.
+ * - We synchronize updates to the read index after having read the data, and
+ *   the write index after having written the data. This means that the each
+ *   thread can only touch a portion of the buffer that is not touched by the
+ *   other thread.
+ * - Callers are expected to provide buffers. When writing to the queue,
+ *   elements are copied into the internal storage from the buffer passed in.
+ *   When reading from the queue, the user is expected to provide a buffer.
+ *   Because this is a ring buffer, data might not be contiguous in memory,
+ *   providing an external buffer to copy into is an easy way to have linear
+ *   data for further processing.
+ */
+template <typename T>
+class RingBuffer {
+public:
+    /**
+     * Constructor for a ring buffer.
+     *
+     * This performs an allocation, but is the only allocation that will happen
+     * for the life time of a `RingBuffer`.
+     *
+     * @param capacity The maximum number of element this ring buffer will hold.
+     */
+    RingBuffer(int capacity)
+        /* One more element to distinguish from empty and full buffer. */
+        : capacity_(capacity + 1) {
+        ASSERT(storage_capacity() < std::numeric_limits<int>::max() / 2 &&
+               "buffer too large for the type of index used.");
+        ASSERT(capacity_ > 0);
+
+        data_.reset(new T[storage_capacity()]);
+        /* If this queue is using atomics, initializing those members as the last
+         * action in the constructor acts as a full barrier, and allow capacity() to
+         * be thread-safe. */
+        write_index_ = 0;
+        read_index_ = 0;
+    }
+    /**
+     * Push `count` zero or default constructed elements in the array.
+     *
+     * Only safely called on the producer thread.
+     *
+     * @param count The number of elements to enqueue.
+     * @return The number of element enqueued.
+     */
+    int enqueue_default(int count) {
+        return enqueue(nullptr, count);
+    }
+    /**
+     * @brief Put an element in the queue
+     *
+     * Only safely called on the producer thread.
+     *
+     * @param element The element to put in the queue.
+     *
+     * @return 1 if the element was inserted, 0 otherwise.
+     */
+    int enqueue(T& element) {
+        return enqueue(&element, 1);
+    }
+    /**
+     * Push `count` elements in the ring buffer.
+     *
+     * Only safely called on the producer thread.
+     *
+     * @param elements a pointer to a buffer containing at least `count` elements.
+     * If `elements` is nullptr, zero or default constructed elements are
+     * enqueued.
+     * @param count The number of elements to read from `elements`
+     * @return The number of elements successfully coped from `elements` and
+     * inserted into the ring buffer.
+     */
+    int enqueue(T* elements, int count) {
+#ifndef NDEBUG
+        assert_correct_thread(producer_id);
+#endif
+
+        int wr_idx = write_index_.load(std::memory_order_relaxed);
+        int rd_idx = read_index_.load(std::memory_order_acquire);
+
+        if (full_internal(rd_idx, wr_idx)) {
+            return 0;
+        }
+
+        int to_write = std::min(available_write_internal(rd_idx, wr_idx), count);
+
+        /* First part, from the write index to the end of the array. */
+        int first_part = std::min(storage_capacity() - wr_idx, to_write);
+        /* Second part, from the beginning of the array */
+        int second_part = to_write - first_part;
+
+        if (elements) {
+            Copy(data_.get() + wr_idx, elements, first_part);
+            Copy(data_.get(), elements + first_part, second_part);
+        } else {
+            ConstructDefault(data_.get() + wr_idx, first_part);
+            ConstructDefault(data_.get(), second_part);
+        }
+
+        write_index_.store(increment_index(wr_idx, to_write), std::memory_order_release);
+
+        return to_write;
+    }
+    /**
+     * Retrieve at most `count` elements from the ring buffer, and copy them to
+     * `elements`, if non-null.
+     *
+     * Only safely called on the consumer side.
+     *
+     * @param elements A pointer to a buffer with space for at least `count`
+     * elements. If `elements` is `nullptr`, `count` element will be discarded.
+     * @param count The maximum number of elements to dequeue.
+     * @return The number of elements written to `elements`.
+     */
+    int dequeue(T* elements, int count) {
+#ifndef NDEBUG
+        assert_correct_thread(consumer_id);
+#endif
+
+        int rd_idx = read_index_.load(std::memory_order_relaxed);
+        int wr_idx = write_index_.load(std::memory_order_acquire);
+
+        if (empty_internal(rd_idx, wr_idx)) {
+            return 0;
+        }
+
+        int to_read = std::min(available_read_internal(rd_idx, wr_idx), count);
+
+        int first_part = std::min(storage_capacity() - rd_idx, to_read);
+        int second_part = to_read - first_part;
+
+        if (elements) {
+            Copy(elements, data_.get() + rd_idx, first_part);
+            Copy(elements + first_part, data_.get(), second_part);
+        }
+
+        read_index_.store(increment_index(rd_idx, to_read), std::memory_order_release);
+
+        return to_read;
+    }
+    /**
+     * Get the number of available element for consuming.
+     *
+     * Only safely called on the consumer thread.
+     *
+     * @return The number of available elements for reading.
+     */
+    int available_read() const {
+#ifndef NDEBUG
+        assert_correct_thread(consumer_id);
+#endif
+        return available_read_internal(read_index_.load(std::memory_order_relaxed),
+                                       write_index_.load(std::memory_order_acquire));
+    }
+    /**
+     * Get the number of available elements for consuming.
+     *
+     * Only safely called on the producer thread.
+     *
+     * @return The number of empty slots in the buffer, available for writing.
+     */
+    int available_write() const {
+#ifndef NDEBUG
+        assert_correct_thread(producer_id);
+#endif
+        return available_write_internal(read_index_.load(std::memory_order_acquire),
+                                        write_index_.load(std::memory_order_relaxed));
+    }
+    /**
+     * Get the total capacity, for this ring buffer.
+     *
+     * Can be called safely on any thread.
+     *
+     * @return The maximum capacity of this ring buffer.
+     */
+    int capacity() const {
+        return storage_capacity() - 1;
+    }
+    /**
+     * Reset the consumer and producer thread identifier, in case the thread are
+     * being changed. This has to be externally synchronized. This is no-op when
+     * asserts are disabled.
+     */
+    void reset_thread_ids() {
+#ifndef NDEBUG
+        consumer_id = producer_id = std::thread::id();
+#endif
+    }
+
+private:
+    /** Return true if the ring buffer is empty.
+     *
+     * @param read_index the read index to consider
+     * @param write_index the write index to consider
+     * @return true if the ring buffer is empty, false otherwise.
+     **/
+    bool empty_internal(int read_index, int write_index) const {
+        return write_index == read_index;
+    }
+    /** Return true if the ring buffer is full.
+     *
+     * This happens if the write index is exactly one element behind the read
+     * index.
+     *
+     * @param read_index the read index to consider
+     * @param write_index the write index to consider
+     * @return true if the ring buffer is full, false otherwise.
+     **/
+    bool full_internal(int read_index, int write_index) const {
+        return (write_index + 1) % storage_capacity() == read_index;
+    }
+    /**
+     * Return the size of the storage. It is one more than the number of elements
+     * that can be stored in the buffer.
+     *
+     * @return the number of elements that can be stored in the buffer.
+     */
+    int storage_capacity() const {
+        return capacity_;
+    }
+    /**
+     * Returns the number of elements available for reading.
+     *
+     * @return the number of available elements for reading.
+     */
+    int available_read_internal(int read_index, int write_index) const {
+        if (write_index >= read_index) {
+            return write_index - read_index;
+        } else {
+            return write_index + storage_capacity() - read_index;
+        }
+    }
+    /**
+     * Returns the number of empty elements, available for writing.
+     *
+     * @return the number of elements that can be written into the array.
+     */
+    int available_write_internal(int read_index, int write_index) const {
+        /* We substract one element here to always keep at least one sample
+         * free in the buffer, to distinguish between full and empty array. */
+        int rv = read_index - write_index - 1;
+        if (write_index >= read_index) {
+            rv += storage_capacity();
+        }
+        return rv;
+    }
+    /**
+     * Increments an index, wrapping it around the storage.
+     *
+     * @param index a reference to the index to increment.
+     * @param increment the number by which `index` is incremented.
+     * @return the new index.
+     */
+    int increment_index(int index, int increment) const {
+        ASSERT(increment >= 0);
+        return (index + increment) % storage_capacity();
+    }
+    /**
+     * @brief This allows checking that enqueue (resp. dequeue) are always called
+     * by the right thread.
+     *
+     * @param id the id of the thread that has called the calling method first.
+     */
+#ifndef NDEBUG
+    static void assert_correct_thread(std::thread::id& id) {
+        if (id == std::thread::id()) {
+            id = std::this_thread::get_id();
+            return;
+        }
+        ASSERT(id == std::this_thread::get_id());
+    }
+#endif
+    /** Similar to memcpy, but accounts for the size of an element. */
+    template <typename CopyT>
+    void PodCopy(CopyT* destination, const CopyT* source, size_t count) {
+        static_assert(std::is_trivial<CopyT>::value, "Requires trivial type");
+        ASSERT(destination && source);
+        memcpy(destination, source, count * sizeof(CopyT));
+    }
+    /** Similar to a memset to zero, but accounts for the size of an element. */
+    template <typename ZeroT>
+    void PodZero(ZeroT* destination, size_t count) {
+        static_assert(std::is_trivial<ZeroT>::value, "Requires trivial type");
+        ASSERT(destination);
+        memset(destination, 0, count * sizeof(ZeroT));
+    }
+    template <typename CopyT, typename Trait>
+    void Copy(CopyT* destination, const CopyT* source, size_t count, Trait) {
+        for (size_t i = 0; i < count; i++) {
+            destination[i] = source[i];
+        }
+    }
+    template <typename CopyT>
+    void Copy(CopyT* destination, const CopyT* source, size_t count, std::true_type) {
+        PodCopy(destination, source, count);
+    }
+    /**
+     * This allows copying a number of elements from a `source` pointer to a
+     * `destination` pointer, using `memcpy` if it is safe to do so, or a loop that
+     * calls the constructors and destructors otherwise.
+     */
+    template <typename CopyT>
+    void Copy(CopyT* destination, const T* source, size_t count) {
+        ASSERT(destination && source);
+        Copy(destination, source, count, typename std::is_trivial<CopyT>::type());
+    }
+    template <typename ConstructT, typename Trait>
+    void ConstructDefault(ConstructT* destination, size_t count, Trait) {
+        for (size_t i = 0; i < count; i++) {
+            destination[i] = ConstructT();
+        }
+    }
+    template <typename ConstructT>
+    void ConstructDefault(ConstructT* destination, size_t count, std::true_type) {
+        PodZero(destination, count);
+    }
+    /**
+     * This allows zeroing (using memset) or default-constructing a number of
+     * elements calling the constructors and destructors if necessary.
+     */
+    template <typename ConstructT>
+    void ConstructDefault(ConstructT* destination, size_t count) {
+        ASSERT(destination);
+        ConstructDefault(destination, count, typename std::is_arithmetic<ConstructT>::type());
+    }
+    /** Index at which the oldest element is at, in samples. */
+    std::atomic<int> read_index_;
+    /** Index at which to write new elements. `write_index` is always at
+     * least one element ahead of `read_index_`. */
+    std::atomic<int> write_index_;
+    /** Maximum number of elements that can be stored in the ring buffer. */
+    const int capacity_;
+    /** Data storage */
+    std::unique_ptr<T[]> data_;
+#ifndef NDEBUG
+    /** The id of the only thread that is allowed to read from the queue. */
+    mutable std::thread::id consumer_id;
+    /** The id of the only thread that is allowed to write from the queue. */
+    mutable std::thread::id producer_id;
+#endif
+};
diff --git a/src/core/libraries/audio/audioout.cpp b/src/core/libraries/audio/audioout.cpp
index db43ee9289e..89ea1d3f530 100644
--- a/src/core/libraries/audio/audioout.cpp
+++ b/src/core/libraries/audio/audioout.cpp
@@ -7,26 +7,15 @@
 #include <magic_enum/magic_enum.hpp>
 
 #include "common/assert.h"
+#include "common/config.h"
 #include "common/logging/log.h"
 #include "core/libraries/audio/audioout.h"
+#include "core/libraries/audio/audioout_backend.h"
 #include "core/libraries/audio/audioout_error.h"
-#include "core/libraries/audio/sdl_audio.h"
 #include "core/libraries/libs.h"
 
 namespace Libraries::AudioOut {
 
-struct PortOut {
-    void* impl;
-    u32 samples_num;
-    u32 freq;
-    OrbisAudioOutParamFormat format;
-    OrbisAudioOutPort type;
-    int channels_num;
-    bool is_float;
-    std::array<int, 8> volume;
-    u8 sample_size;
-    bool is_open;
-};
 std::shared_mutex ports_mutex;
 std::array<PortOut, SCE_AUDIO_OUT_NUM_PORTS> ports_out{};
 
@@ -104,7 +93,7 @@ static bool IsFormatFloat(const OrbisAudioOutParamFormat format) {
     }
 }
 
-static int GetFormatNumChannels(const OrbisAudioOutParamFormat format) {
+static u8 GetFormatNumChannels(const OrbisAudioOutParamFormat format) {
     switch (format) {
     case OrbisAudioOutParamFormat::S16Mono:
     case OrbisAudioOutParamFormat::FloatMono:
@@ -187,13 +176,11 @@ int PS4_SYSV_ABI sceAudioOutClose(s32 handle) {
 
     std::scoped_lock lock(ports_mutex);
     auto& port = ports_out.at(handle - 1);
-    if (!port.is_open) {
+    if (!port.impl) {
         return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
     }
 
-    audio->Close(port.impl);
     port.impl = nullptr;
-    port.is_open = false;
     return ORBIS_OK;
 }
 
@@ -264,7 +251,7 @@ int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* sta
 
     std::scoped_lock lock(ports_mutex);
     const auto& port = ports_out.at(handle - 1);
-    if (!port.is_open) {
+    if (!port.impl) {
         return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
     }
 
@@ -324,7 +311,16 @@ int PS4_SYSV_ABI sceAudioOutInit() {
     if (audio != nullptr) {
         return ORBIS_AUDIO_OUT_ERROR_ALREADY_INIT;
     }
-    audio = std::make_unique<SDLAudioOut>();
+    const auto backend = Config::getAudioBackend();
+    if (backend == "cubeb") {
+        audio = std::make_unique<CubebAudioOut>();
+    } else if (backend == "sdl") {
+        audio = std::make_unique<SDLAudioOut>();
+    } else {
+        // Cubeb as a default fallback.
+        LOG_ERROR(Lib_AudioOut, "Invalid audio backend '{}', defaulting to cubeb.", backend);
+        audio = std::make_unique<CubebAudioOut>();
+    }
     return ORBIS_OK;
 }
 
@@ -399,23 +395,25 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
     }
 
     std::scoped_lock lock{ports_mutex};
-    const auto port = std::ranges::find(ports_out, false, &PortOut::is_open);
+    const auto port =
+        std::ranges::find_if(ports_out, [&](const PortOut& p) { return p.impl == nullptr; });
     if (port == ports_out.end()) {
         LOG_ERROR(Lib_AudioOut, "Audio ports are full");
         return ORBIS_AUDIO_OUT_ERROR_PORT_FULL;
     }
 
-    port->is_open = true;
     port->type = port_type;
-    port->samples_num = length;
-    port->freq = sample_rate;
     port->format = format;
     port->is_float = IsFormatFloat(format);
-    port->channels_num = GetFormatNumChannels(format);
     port->sample_size = GetFormatSampleSize(format);
+    port->channels_num = GetFormatNumChannels(format);
+    port->samples_num = length;
+    port->frame_size = port->sample_size * port->channels_num;
+    port->buffer_size = port->frame_size * port->samples_num;
+    port->freq = sample_rate;
     port->volume.fill(SCE_AUDIO_OUT_VOLUME_0DB);
+    port->impl = audio->Open(*port);
 
-    port->impl = audio->Open(port->is_float, port->channels_num, port->freq);
     return std::distance(ports_out.begin(), port) + 1;
 }
 
@@ -424,7 +422,7 @@ int PS4_SYSV_ABI sceAudioOutOpenEx() {
     return ORBIS_OK;
 }
 
-s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, const void* ptr) {
+s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, void* ptr) {
     if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) {
         return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
     }
@@ -434,12 +432,11 @@ s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, const void* ptr) {
     }
 
     auto& port = ports_out.at(handle - 1);
-    if (!port.is_open) {
+    if (!port.impl) {
         return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
     }
 
-    const size_t data_size = port.samples_num * port.sample_size * port.channels_num;
-    audio->Output(port.impl, ptr, data_size);
+    port.impl->Output(ptr, port.buffer_size);
     return ORBIS_OK;
 }
 
@@ -548,7 +545,7 @@ s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) {
 
     std::scoped_lock lock(ports_mutex);
     auto& port = ports_out.at(handle - 1);
-    if (!port.is_open) {
+    if (!port.impl) {
         return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
     }
 
@@ -579,7 +576,7 @@ s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) {
         }
     }
 
-    audio->SetVolume(port.impl, port.volume);
+    port.impl->SetVolume(port.volume);
     return ORBIS_OK;
 }
 
diff --git a/src/core/libraries/audio/audioout.h b/src/core/libraries/audio/audioout.h
index c66a0e9f5ff..58c77db99c4 100644
--- a/src/core/libraries/audio/audioout.h
+++ b/src/core/libraries/audio/audioout.h
@@ -3,12 +3,15 @@
 
 #pragma once
 
-#include "common/bit_field.h"
+#include <memory>
 
+#include "common/bit_field.h"
 #include "core/libraries/system/userservice.h"
 
 namespace Libraries::AudioOut {
 
+class PortBackend;
+
 // Main up to 8 ports, BGM 1 port, voice up to 4 ports,
 // personal up to 4 ports, padspk up to 5 ports, aux 1 port
 constexpr int SCE_AUDIO_OUT_NUM_PORTS = 22;
@@ -43,7 +46,7 @@ union OrbisAudioOutParamExtendedInformation {
 
 struct OrbisAudioOutOutputParam {
     s32 handle;
-    const void* ptr;
+    void* ptr;
 };
 
 struct OrbisAudioOutPortState {
@@ -56,6 +59,21 @@ struct OrbisAudioOutPortState {
     u64 reserved64[2];
 };
 
+struct PortOut {
+    std::unique_ptr<PortBackend> impl{};
+
+    OrbisAudioOutPort type;
+    OrbisAudioOutParamFormat format;
+    bool is_float;
+    u8 sample_size;
+    u8 channels_num;
+    u32 samples_num;
+    u32 frame_size;
+    u32 buffer_size;
+    u32 freq;
+    std::array<int, 8> volume;
+};
+
 int PS4_SYSV_ABI sceAudioOutDeviceIdOpen();
 int PS4_SYSV_ABI sceAudioDeviceControlGet();
 int PS4_SYSV_ABI sceAudioDeviceControlSet();
@@ -94,7 +112,7 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
                                  OrbisAudioOutPort port_type, s32 index, u32 length,
                                  u32 sample_rate, OrbisAudioOutParamExtendedInformation param_type);
 int PS4_SYSV_ABI sceAudioOutOpenEx();
-s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, const void* ptr);
+s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, void* ptr);
 s32 PS4_SYSV_ABI sceAudioOutOutputs(OrbisAudioOutOutputParam* param, u32 num);
 int PS4_SYSV_ABI sceAudioOutPtClose();
 int PS4_SYSV_ABI sceAudioOutPtGetLastOutputTime();
diff --git a/src/core/libraries/audio/audioout_backend.h b/src/core/libraries/audio/audioout_backend.h
index 238ef0201c3..ecc4cf7c689 100644
--- a/src/core/libraries/audio/audioout_backend.h
+++ b/src/core/libraries/audio/audioout_backend.h
@@ -3,17 +3,42 @@
 
 #pragma once
 
+typedef struct cubeb cubeb;
+
 namespace Libraries::AudioOut {
 
+struct PortOut;
+
+class PortBackend {
+public:
+    virtual ~PortBackend() = default;
+
+    virtual void Output(void* ptr, size_t size) = 0;
+    virtual void SetVolume(const std::array<int, 8>& ch_volumes) = 0;
+};
+
 class AudioOutBackend {
 public:
     AudioOutBackend() = default;
     virtual ~AudioOutBackend() = default;
 
-    virtual void* Open(bool is_float, int num_channels, u32 sample_rate) = 0;
-    virtual void Close(void* impl) = 0;
-    virtual void Output(void* impl, const void* ptr, size_t size) = 0;
-    virtual void SetVolume(void* impl, std::array<int, 8> ch_volumes) = 0;
+    virtual std::unique_ptr<PortBackend> Open(PortOut& port) = 0;
+};
+
+class CubebAudioOut final : public AudioOutBackend {
+public:
+    CubebAudioOut();
+    ~CubebAudioOut() override;
+
+    std::unique_ptr<PortBackend> Open(PortOut& port) override;
+
+private:
+    cubeb* ctx = nullptr;
+};
+
+class SDLAudioOut final : public AudioOutBackend {
+public:
+    std::unique_ptr<PortBackend> Open(PortOut& port) override;
 };
 
 } // namespace Libraries::AudioOut
diff --git a/src/core/libraries/audio/cubeb_audio.cpp b/src/core/libraries/audio/cubeb_audio.cpp
new file mode 100644
index 00000000000..ca0a4c3b6a1
--- /dev/null
+++ b/src/core/libraries/audio/cubeb_audio.cpp
@@ -0,0 +1,158 @@
+// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <condition_variable>
+#include <mutex>
+#include <cubeb/cubeb.h>
+
+#include "common/assert.h"
+#include "common/ringbuffer.h"
+#include "core/libraries/audio/audioout.h"
+#include "core/libraries/audio/audioout_backend.h"
+
+namespace Libraries::AudioOut {
+
+constexpr int AUDIO_STREAM_BUFFER_THRESHOLD = 65536; // Define constant for buffer threshold
+
+class CubebPortBackend : public PortBackend {
+public:
+    CubebPortBackend(cubeb* ctx, const PortOut& port)
+        : frame_size(port.frame_size), buffer(static_cast<int>(port.buffer_size) * 4) {
+        if (!ctx) {
+            return;
+        }
+        const auto get_channel_layout = [&port] -> cubeb_channel_layout {
+            switch (port.channels_num) {
+            case 1:
+                return CUBEB_LAYOUT_MONO;
+            case 2:
+                return CUBEB_LAYOUT_STEREO;
+            case 8:
+                return CUBEB_LAYOUT_3F4_LFE;
+            default:
+                UNREACHABLE();
+            }
+        };
+        cubeb_stream_params stream_params = {
+            .format = port.is_float ? CUBEB_SAMPLE_FLOAT32LE : CUBEB_SAMPLE_S16LE,
+            .rate = port.freq,
+            .channels = port.channels_num,
+            .layout = get_channel_layout(),
+            .prefs = CUBEB_STREAM_PREF_NONE,
+        };
+        u32 latency_frames = 512;
+        if (const auto ret = cubeb_get_min_latency(ctx, &stream_params, &latency_frames);
+            ret != CUBEB_OK) {
+            LOG_WARNING(Lib_AudioOut,
+                        "Could not get minimum cubeb audio latency, falling back to default: {}",
+                        ret);
+        }
+        char stream_name[64];
+        snprintf(stream_name, sizeof(stream_name), "shadPS4 stream %p", this);
+        if (const auto ret = cubeb_stream_init(ctx, &stream, stream_name, nullptr, nullptr, nullptr,
+                                               &stream_params, latency_frames, &DataCallback,
+                                               &StateCallback, this);
+            ret != CUBEB_OK) {
+            LOG_ERROR(Lib_AudioOut, "Failed to create cubeb stream: {}", ret);
+            return;
+        }
+        if (const auto ret = cubeb_stream_start(stream); ret != CUBEB_OK) {
+            LOG_ERROR(Lib_AudioOut, "Failed to start cubeb stream: {}", ret);
+            return;
+        }
+    }
+
+    ~CubebPortBackend() override {
+        if (!stream) {
+            return;
+        }
+        if (const auto ret = cubeb_stream_stop(stream); ret != CUBEB_OK) {
+            LOG_WARNING(Lib_AudioOut, "Failed to stop cubeb stream: {}", ret);
+        }
+        cubeb_stream_destroy(stream);
+        stream = nullptr;
+    }
+
+    void Output(void* ptr, size_t size) override {
+        auto* data = static_cast<u8*>(ptr);
+
+        std::unique_lock lock{buffer_mutex};
+        buffer_cv.wait(lock, [&] { return buffer.available_write() >= size; });
+        buffer.enqueue(data, static_cast<int>(size));
+    }
+
+    void SetVolume(const std::array<int, 8>& ch_volumes) override {
+        if (!stream) {
+            return;
+        }
+        // Cubeb does not have per-channel volumes, for now just take the maximum of the channels.
+        const auto vol = *std::ranges::max_element(ch_volumes);
+        if (const auto ret =
+                cubeb_stream_set_volume(stream, static_cast<float>(vol) / SCE_AUDIO_OUT_VOLUME_0DB);
+            ret != CUBEB_OK) {
+            LOG_WARNING(Lib_AudioOut, "Failed to change cubeb stream volume: {}", ret);
+        }
+    }
+
+private:
+    static long DataCallback(cubeb_stream* stream, void* user_data, const void* in, void* out,
+                             long num_frames) {
+        auto* stream_data = static_cast<CubebPortBackend*>(user_data);
+        const auto out_data = static_cast<u8*>(out);
+        const auto requested_size = static_cast<int>(num_frames * stream_data->frame_size);
+
+        std::unique_lock lock{stream_data->buffer_mutex};
+        const auto dequeued_size = stream_data->buffer.dequeue(out_data, requested_size);
+        lock.unlock();
+        stream_data->buffer_cv.notify_one();
+
+        if (dequeued_size < requested_size) {
+            // Need to fill remaining space with silence.
+            std::memset(out_data + dequeued_size, 0, requested_size - dequeued_size);
+        }
+        return num_frames;
+    }
+
+    static void StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {
+        switch (state) {
+        case CUBEB_STATE_STARTED:
+            LOG_INFO(Lib_AudioOut, "Cubeb stream started");
+            break;
+        case CUBEB_STATE_STOPPED:
+            LOG_INFO(Lib_AudioOut, "Cubeb stream stopped");
+            break;
+        case CUBEB_STATE_DRAINED:
+            LOG_INFO(Lib_AudioOut, "Cubeb stream drained");
+            break;
+        case CUBEB_STATE_ERROR:
+            LOG_ERROR(Lib_AudioOut, "Cubeb stream encountered an error");
+            break;
+        }
+    }
+
+    size_t frame_size;
+    RingBuffer<u8> buffer;
+    std::mutex buffer_mutex;
+    std::condition_variable buffer_cv;
+    cubeb_stream* stream{};
+};
+
+CubebAudioOut::CubebAudioOut() {
+    if (const auto ret = cubeb_init(&ctx, "shadPS4", nullptr); ret != CUBEB_OK) {
+        LOG_CRITICAL(Lib_AudioOut, "Failed to create cubeb context: {}", ret);
+    }
+}
+
+CubebAudioOut::~CubebAudioOut() {
+    if (!ctx) {
+        return;
+    }
+    cubeb_destroy(ctx);
+    ctx = nullptr;
+}
+
+std::unique_ptr<PortBackend> CubebAudioOut::Open(PortOut& port) {
+    return std::make_unique<CubebPortBackend>(ctx, port);
+}
+
+} // namespace Libraries::AudioOut
diff --git a/src/core/libraries/audio/sdl_audio.cpp b/src/core/libraries/audio/sdl_audio.cpp
index ce385ad9cf1..7d7a7cee59e 100644
--- a/src/core/libraries/audio/sdl_audio.cpp
+++ b/src/core/libraries/audio/sdl_audio.cpp
@@ -1,44 +1,60 @@
 // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
 // SPDX-License-Identifier: GPL-2.0-or-later
 
+#include <thread>
+
 #include <SDL3/SDL_audio.h>
 #include <SDL3/SDL_init.h>
-#include <SDL3/SDL_timer.h>
 
-#include "common/assert.h"
-#include "core/libraries/audio/sdl_audio.h"
+#include "common/logging/log.h"
+#include "core/libraries/audio/audioout.h"
+#include "core/libraries/audio/audioout_backend.h"
 
 namespace Libraries::AudioOut {
 
 constexpr int AUDIO_STREAM_BUFFER_THRESHOLD = 65536; // Define constant for buffer threshold
 
-void* SDLAudioOut::Open(bool is_float, int num_channels, u32 sample_rate) {
-    SDL_AudioSpec fmt;
-    SDL_zero(fmt);
-    fmt.format = is_float ? SDL_AUDIO_F32 : SDL_AUDIO_S16;
-    fmt.channels = num_channels;
-    fmt.freq = sample_rate;
-
-    auto* stream =
-        SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, nullptr, nullptr);
-    SDL_ResumeAudioStreamDevice(stream);
-    return stream;
-}
+class SDLPortBackend : public PortBackend {
+public:
+    explicit SDLPortBackend(const PortOut& port) {
+        const SDL_AudioSpec fmt = {
+            .format = port.is_float ? SDL_AUDIO_F32 : SDL_AUDIO_S16,
+            .channels = port.channels_num,
+            .freq = static_cast<int>(port.freq),
+        };
+        stream =
+            SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, nullptr, nullptr);
+        if (stream == nullptr) {
+            LOG_ERROR(Lib_AudioOut, "Failed to create SDL audio stream: {}", SDL_GetError());
+        }
+        SDL_ResumeAudioStreamDevice(stream);
+    }
 
-void SDLAudioOut::Close(void* impl) {
-    SDL_DestroyAudioStream(static_cast<SDL_AudioStream*>(impl));
-}
+    ~SDLPortBackend() override {
+        if (stream) {
+            SDL_DestroyAudioStream(stream);
+            stream = nullptr;
+        }
+    }
 
-void SDLAudioOut::Output(void* impl, const void* ptr, size_t size) {
-    auto* stream = static_cast<SDL_AudioStream*>(impl);
-    SDL_PutAudioStreamData(stream, ptr, size);
-    while (SDL_GetAudioStreamAvailable(stream) > AUDIO_STREAM_BUFFER_THRESHOLD) {
-        SDL_Delay(0);
+    void Output(void* ptr, size_t size) override {
+        SDL_PutAudioStreamData(stream, ptr, static_cast<int>(size));
+        while (SDL_GetAudioStreamAvailable(stream) > AUDIO_STREAM_BUFFER_THRESHOLD) {
+            // Yield to allow the stream to drain.
+            std::this_thread::yield();
+        }
     }
-}
 
-void SDLAudioOut::SetVolume(void* impl, std::array<int, 8> ch_volumes) {
-    // Not yet implemented
+    void SetVolume(const std::array<int, 8>& ch_volumes) override {
+        // TODO: Not yet implemented
+    }
+
+private:
+    SDL_AudioStream* stream;
+};
+
+std::unique_ptr<PortBackend> SDLAudioOut::Open(PortOut& port) {
+    return std::make_unique<SDLPortBackend>(port);
 }
 
 } // namespace Libraries::AudioOut
diff --git a/src/core/libraries/audio/sdl_audio.h b/src/core/libraries/audio/sdl_audio.h
deleted file mode 100644
index d55f2f6e3d1..00000000000
--- a/src/core/libraries/audio/sdl_audio.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "core/libraries/audio/audioout_backend.h"
-
-namespace Libraries::AudioOut {
-
-class SDLAudioOut final : public AudioOutBackend {
-public:
-    void* Open(bool is_float, int num_channels, u32 sample_rate) override;
-    void Close(void* impl) override;
-    void Output(void* impl, const void* ptr, size_t size) override;
-    void SetVolume(void* impl, std::array<int, 8> ch_volumes) override;
-};
-
-} // namespace Libraries::AudioOut
diff --git a/src/core/libraries/kernel/threads/pthread.cpp b/src/core/libraries/kernel/threads/pthread.cpp
index 610e6123883..761d133460a 100644
--- a/src/core/libraries/kernel/threads/pthread.cpp
+++ b/src/core/libraries/kernel/threads/pthread.cpp
@@ -244,8 +244,8 @@ int PS4_SYSV_ABI posix_pthread_create_name_np(PthreadT* thread, const PthreadAtt
     new_thread->tid = ++TidCounter;
 
     if (new_thread->attr.stackaddr_attr == 0) {
-        /* Enforce minimum stack size of 64 KB */
-        static constexpr size_t MinimumStack = 64_KB;
+        /* Enforce minimum stack size of 128 KB */
+        static constexpr size_t MinimumStack = 128_KB;
         auto& stacksize = new_thread->attr.stacksize_attr;
         stacksize = std::max(stacksize, MinimumStack);
     }
diff --git a/src/emulator.cpp b/src/emulator.cpp
index 11a9f42f214..10d17a2db4a 100644
--- a/src/emulator.cpp
+++ b/src/emulator.cpp
@@ -322,7 +322,7 @@ void Emulator::LoadSystemModules(const std::filesystem::path& file, std::string
             LOG_INFO(Loader, "No HLE available for {} module", module_name);
         }
     }
-    if (std::filesystem::exists(sys_module_path / game_serial)) {
+    if (!game_serial.empty() && std::filesystem::exists(sys_module_path / game_serial)) {
         for (const auto& entry :
              std::filesystem::directory_iterator(sys_module_path / game_serial)) {
             LOG_INFO(Loader, "Loading {} from game serial file {}", entry.path().string(),
diff --git a/src/qt_gui/settings_dialog.cpp b/src/qt_gui/settings_dialog.cpp
index f9095d8a05a..df802901afa 100644
--- a/src/qt_gui/settings_dialog.cpp
+++ b/src/qt_gui/settings_dialog.cpp
@@ -212,6 +212,7 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
         ui->enableCompatibilityCheckBox->installEventFilter(this);
         ui->checkCompatibilityOnStartupCheckBox->installEventFilter(this);
         ui->updateCompatibilityButton->installEventFilter(this);
+        ui->audioBackendComboBox->installEventFilter(this);
 
         // Input
         ui->hideCursorGroupBox->installEventFilter(this);
@@ -306,6 +307,8 @@ void SettingsDialog::LoadValuesFromConfig() {
         toml::find_or<bool>(data, "General", "compatibilityEnabled", false));
     ui->checkCompatibilityOnStartupCheckBox->setChecked(
         toml::find_or<bool>(data, "General", "checkCompatibilityOnStartup", false));
+    ui->audioBackendComboBox->setCurrentText(
+        QString::fromStdString(toml::find_or<std::string>(data, "Audio", "backend", "cubeb")));
 
 #ifdef ENABLE_UPDATER
     ui->updateCheckBox->setChecked(toml::find_or<bool>(data, "General", "autoUpdate", false));
@@ -429,6 +432,8 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
         text = tr("checkCompatibilityOnStartupCheckBox");
     } else if (elementName == "updateCompatibilityButton") {
         text = tr("updateCompatibilityButton");
+    } else if (elementName == "audioBackendGroupBox") {
+        text = tr("audioBackendGroupBox");
     }
 
     // Input
@@ -544,6 +549,7 @@ void SettingsDialog::UpdateSettings() {
     Config::setUpdateChannel(ui->updateComboBox->currentText().toStdString());
     Config::setCompatibilityEnabled(ui->enableCompatibilityCheckBox->isChecked());
     Config::setCheckCompatibilityOnStartup(ui->checkCompatibilityOnStartupCheckBox->isChecked());
+    Config::setAudioBackend(ui->audioBackendComboBox->currentText().toStdString());
 
 #ifdef ENABLE_DISCORD_RPC
     auto* rpc = Common::Singleton<DiscordRPCHandler::RPC>::Instance();
diff --git a/src/qt_gui/settings_dialog.ui b/src/qt_gui/settings_dialog.ui
index 4d69ee5b103..0af133e3e26 100644
--- a/src/qt_gui/settings_dialog.ui
+++ b/src/qt_gui/settings_dialog.ui
@@ -270,6 +270,29 @@
                  </item>
                 </layout>
                </item>
+               <item>
+                <widget class="QGroupBox" name="audioBackendGroupBox">
+                 <property name="title">
+                  <string>Audio Backend</string>
+                 </property>
+                 <layout class="QVBoxLayout" name="audioBackendBoxLayout">
+                  <item>
+                   <widget class="QComboBox" name="audioBackendComboBox">
+                    <item>
+                     <property name="text">
+                      <string>cubeb</string>
+                     </property>
+                    </item>
+                    <item>
+                     <property name="text">
+                      <string>sdl</string>
+                     </property>
+                    </item>
+                   </widget>
+                  </item>
+                 </layout>
+                </widget>
+               </item>
               </layout>
              </widget>
             </item>

From 115aa61d040e8ed0f6d68624d3bec0b5f2e945c7 Mon Sep 17 00:00:00 2001
From: squidbus <175574877+squidbus@users.noreply.github.com>
Date: Fri, 27 Dec 2024 12:10:16 -0800
Subject: [PATCH 3/6] build: Fix MoltenVK bundling copy. (#1928)

---
 CMakeLists.txt | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5c236660153..736cf2803c8 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -904,11 +904,18 @@ endif()
 if (APPLE)
   if (ENABLE_QT_GUI)
       # Include MoltenVK in the app bundle, along with an ICD file so it can be found by the system Vulkan loader if used for loading layers.
-      set(MVK_DYLIB ${CMAKE_CURRENT_BINARY_DIR}/externals/MoltenVK/libMoltenVK.dylib)
       set(MVK_ICD ${CMAKE_CURRENT_SOURCE_DIR}/externals/MoltenVK/MoltenVK_icd.json)
-      target_sources(shadps4 PRIVATE ${MVK_DYLIB} ${MVK_ICD})
-      set_source_files_properties(${MVK_DYLIB} PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks)
+      target_sources(shadps4 PRIVATE ${MVK_ICD})
       set_source_files_properties(${MVK_ICD} PROPERTIES MACOSX_PACKAGE_LOCATION Resources/vulkan/icd.d)
+
+      set(MVK_DYLIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/externals/MoltenVK/libMoltenVK.dylib)
+      set(MVK_DYLIB_DST ${CMAKE_CURRENT_BINARY_DIR}/shadps4.app/Contents/Frameworks/libMoltenVK.dylib)
+      add_custom_command(
+          OUTPUT ${MVK_DYLIB_DST}
+          DEPENDS ${MVK_DYLIB_SRC}
+          COMMAND cmake -E copy ${MVK_DYLIB_SRC} ${MVK_DYLIB_DST})
+      add_custom_target(CopyMoltenVK DEPENDS ${MVK_DYLIB_DST})
+      add_dependencies(shadps4 CopyMoltenVK)
       set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path/../Frameworks")
   else()
       # For non-bundled SDL build, just do a normal library link.

From f4c1d827d5b6bb47c93205d8c239b9bff61afbb9 Mon Sep 17 00:00:00 2001
From: squidbus <175574877+squidbus@users.noreply.github.com>
Date: Fri, 27 Dec 2024 12:20:30 -0800
Subject: [PATCH 4/6] build: Do not generate files in source. (#1929)

---
 CMakeLists.txt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 736cf2803c8..43e8d7cabdd 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -106,7 +106,7 @@ git_describe(GIT_DESC --always --long --dirty)
 git_branch_name(GIT_BRANCH)
 string(TIMESTAMP BUILD_DATE "%Y-%m-%d %H:%M:%S")
 
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp" @ONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/common/scm_rev.cpp" @ONLY)
 
 find_package(Boost 1.84.0 CONFIG)
 find_package(FFmpeg 5.1.2 MODULE)
@@ -520,7 +520,7 @@ set(COMMON src/common/logging/backend.cpp
            src/common/number_utils.cpp
            src/common/memory_patcher.h
            src/common/memory_patcher.cpp
-           src/common/scm_rev.cpp
+           ${CMAKE_CURRENT_BINARY_DIR}/src/common/scm_rev.cpp
            src/common/scm_rev.h
 )
 

From abe85fd3e005976c64048972d34dea31dd6f7f08 Mon Sep 17 00:00:00 2001
From: DanielSvoboda <daniel.svoboda@hotmail.com>
Date: Fri, 27 Dec 2024 17:23:11 -0300
Subject: [PATCH 5/6] GUI: Fix TR Units - Size and Time - more... (#1927)

* GUI: TR Units - Size and Time

Added translation for these units:
B, KB, MB, GB, TB
h, m, s

Added missing text:
Games: - text in the lower left corner
Compatibility...
Update database
View report
Submit a report

Fixed the size of the settings menu

* Audio Backend

* Fixed the size of the settings menu
---
 src/qt_gui/game_list_frame.cpp   |  6 +--
 src/qt_gui/game_list_utils.h     |  5 ++-
 src/qt_gui/main_window.cpp       |  4 +-
 src/qt_gui/settings_dialog.ui    |  4 +-
 src/qt_gui/translations/ar.ts    | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/da_DK.ts | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/de.ts    | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/el.ts    | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/en.ts    | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/es_ES.ts | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/fa_IR.ts | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/fi.ts    | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/fr.ts    | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/hu_HU.ts | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/id.ts    | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/it.ts    | 75 +++++++++++++++++++++++++++++++-
 src/qt_gui/translations/ja_JP.ts | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/ko_KR.ts | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/lt_LT.ts | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/nb.ts    | 75 +++++++++++++++++++++++++++++++-
 src/qt_gui/translations/nl.ts    | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/pl_PL.ts | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/pt_BR.ts | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/ro_RO.ts | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/ru_RU.ts | 53 ++++++++++++++++++++++
 src/qt_gui/translations/sq.ts    | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/tr_TR.ts | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/uk_UA.ts | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/vi_VN.ts | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/zh_CN.ts | 73 +++++++++++++++++++++++++++++++
 src/qt_gui/translations/zh_TW.ts | 73 +++++++++++++++++++++++++++++++
 31 files changed, 1963 insertions(+), 11 deletions(-)

diff --git a/src/qt_gui/game_list_frame.cpp b/src/qt_gui/game_list_frame.cpp
index bba3c289172..b1cd0721617 100644
--- a/src/qt_gui/game_list_frame.cpp
+++ b/src/qt_gui/game_list_frame.cpp
@@ -133,16 +133,16 @@ void GameListFrame::PopulateGameList() {
 
             QString formattedPlayTime;
             if (hours > 0) {
-                formattedPlayTime += QString("%1h ").arg(hours);
+                formattedPlayTime += QString("%1").arg(hours) + tr("h");
             }
             if (minutes > 0) {
-                formattedPlayTime += QString("%1m ").arg(minutes);
+                formattedPlayTime += QString("%1").arg(minutes) + tr("m");
             }
 
             formattedPlayTime = formattedPlayTime.trimmed();
             m_game_info->m_games[i].play_time = playTime.toStdString();
             if (formattedPlayTime.isEmpty()) {
-                SetTableItem(i, 8, QString("%1s").arg(seconds));
+                SetTableItem(i, 8, QString("%1").arg(seconds) + tr("s"));
             } else {
                 SetTableItem(i, 8, formattedPlayTime);
             }
diff --git a/src/qt_gui/game_list_utils.h b/src/qt_gui/game_list_utils.h
index 16c0307c82c..ab923388653 100644
--- a/src/qt_gui/game_list_utils.h
+++ b/src/qt_gui/game_list_utils.h
@@ -30,10 +30,11 @@ struct GameInfo {
     CompatibilityEntry compatibility = CompatibilityEntry{CompatibilityStatus::Unknown};
 };
 
-class GameListUtils {
+class GameListUtils : public QObject {
+    Q_OBJECT
 public:
     static QString FormatSize(qint64 size) {
-        static const QStringList suffixes = {"B", "KB", "MB", "GB", "TB"};
+        static const QStringList suffixes = {tr("B"), tr("KB"), tr("MB"), tr("GB"), tr("TB")};
         int suffixIndex = 0;
 
         double gameSize = static_cast<double>(size);
diff --git a/src/qt_gui/main_window.cpp b/src/qt_gui/main_window.cpp
index 4a9b4d94af2..724e008aea5 100644
--- a/src/qt_gui/main_window.cpp
+++ b/src/qt_gui/main_window.cpp
@@ -75,8 +75,8 @@ bool MainWindow::Init() {
     this->setStatusBar(statusBar.data());
     // Update status bar
     int numGames = m_game_info->m_games.size();
-    QString statusMessage =
-        "Games: " + QString::number(numGames) + " (" + QString::number(duration.count()) + "ms)";
+    QString statusMessage = tr("Games: ") + QString::number(numGames) + " (" +
+                            QString::number(duration.count()) + "ms)";
     statusBar->showMessage(statusMessage);
 
 #ifdef ENABLE_DISCORD_RPC
diff --git a/src/qt_gui/settings_dialog.ui b/src/qt_gui/settings_dialog.ui
index 0af133e3e26..c18b704973d 100644
--- a/src/qt_gui/settings_dialog.ui
+++ b/src/qt_gui/settings_dialog.ui
@@ -11,8 +11,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>900</width>
-    <height>660</height>
+    <width>950</width>
+    <height>780</height>
    </rect>
   </property>
   <property name="sizePolicy">
diff --git a/src/qt_gui/translations/ar.ts b/src/qt_gui/translations/ar.ts
index cd71e083cc2..1f65db04abe 100644
--- a/src/qt_gui/translations/ar.ts
+++ b/src/qt_gui/translations/ar.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Delete DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>مهلة إخفاء المؤشر عند الخمول</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>الصوت</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>فشل في إنشاء ملف سكريبت التحديث</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/da_DK.ts b/src/qt_gui/translations/da_DK.ts
index 677789d495f..943e2d092dd 100644
--- a/src/qt_gui/translations/da_DK.ts
+++ b/src/qt_gui/translations/da_DK.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Delete DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Timeout for skjul markør ved inaktivitet</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Lydstyrke</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Kunne ikke oprette opdateringsscriptfilen</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/de.ts b/src/qt_gui/translations/de.ts
index 64770f6fe3e..cbbef821516 100644
--- a/src/qt_gui/translations/de.ts
+++ b/src/qt_gui/translations/de.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Delete DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Inaktivitätszeitüberschreitung zum Ausblenden des Cursors</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Lautstärke</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Fehler beim Erstellen der Aktualisierungs-Skriptdatei</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/el.ts b/src/qt_gui/translations/el.ts
index 05faa7bc9a8..8737f52169a 100644
--- a/src/qt_gui/translations/el.ts
+++ b/src/qt_gui/translations/el.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Delete DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Χρόνος αδράνειας απόκρυψης δείκτη</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>ένταση</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Αποτυχία δημιουργίας του αρχείου σεναρίου ενημέρωσης</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/en.ts b/src/qt_gui/translations/en.ts
index b616b889aea..692aa527ea8 100644
--- a/src/qt_gui/translations/en.ts
+++ b/src/qt_gui/translations/en.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Delete DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Hide Cursor Idle Timeout</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Volume</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Failed to create the update script file</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/es_ES.ts b/src/qt_gui/translations/es_ES.ts
index 9b8b3812935..70be2253d89 100644
--- a/src/qt_gui/translations/es_ES.ts
+++ b/src/qt_gui/translations/es_ES.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Delete DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Tiempo de espera para ocultar cursor inactivo</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Volumen</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>No se pudo crear el archivo del script de actualización</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/fa_IR.ts b/src/qt_gui/translations/fa_IR.ts
index 66ec0b4c0f6..54187cf9b03 100644
--- a/src/qt_gui/translations/fa_IR.ts
+++ b/src/qt_gui/translations/fa_IR.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>حذف محتوای اضافی (DLC)</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="173"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>مخفی کردن زمان توقف مکان نما</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>صدا</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>هرگز بازی نشده</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>فایل اسکریپت به روز رسانی ایجاد نشد</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
diff --git a/src/qt_gui/translations/fi.ts b/src/qt_gui/translations/fi.ts
index 67ea079aa43..bdc1eb703d1 100644
--- a/src/qt_gui/translations/fi.ts
+++ b/src/qt_gui/translations/fi.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Delete DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Inaktiivisuuden aikaraja kursorin piilottamiselle</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Äänenvoimakkuus</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Päivitysskripttitiedoston luominen epäonnistui</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/fr.ts b/src/qt_gui/translations/fr.ts
index c092580a848..19b0f935863 100644
--- a/src/qt_gui/translations/fr.ts
+++ b/src/qt_gui/translations/fr.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Supprimer DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Délai d'inactivité pour masquer le curseur</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Volume</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Jamais joué</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Échec de la création du fichier de script de mise à jour</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/hu_HU.ts b/src/qt_gui/translations/hu_HU.ts
index 7e60001f674..bc337f2cdf5 100644
--- a/src/qt_gui/translations/hu_HU.ts
+++ b/src/qt_gui/translations/hu_HU.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>DLC-k törlése</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="173"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Kurzor inaktivitási időtúllépés</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Hangerő</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>A frissítési szkript fájl létrehozása nem sikerült</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/id.ts b/src/qt_gui/translations/id.ts
index 31f377341b1..7a0bf5d05d0 100644
--- a/src/qt_gui/translations/id.ts
+++ b/src/qt_gui/translations/id.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Delete DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Batas waktu sembunyikan kursor tidak aktif</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Volume</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Gagal membuat file skrip pembaruan</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/it.ts b/src/qt_gui/translations/it.ts
index 8dc0817f1aa..1391fbc55d9 100644
--- a/src/qt_gui/translations/it.ts
+++ b/src/qt_gui/translations/it.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Elimina DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Timeout inattività per nascondere il cursore</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Volume</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Mai Giocato</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Impossibile creare il file di script di aggiornamento</translation>
 		</message>
 	</context>
-</TS>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
+</TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/ja_JP.ts b/src/qt_gui/translations/ja_JP.ts
index 43fb37c2cbe..58f213e032f 100644
--- a/src/qt_gui/translations/ja_JP.ts
+++ b/src/qt_gui/translations/ja_JP.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Delete DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>カーソル非アクティブタイムアウト</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>音量</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>アップデートスクリプトファイルの作成に失敗しました</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/ko_KR.ts b/src/qt_gui/translations/ko_KR.ts
index ffaa8404fbd..75a1b53cf44 100644
--- a/src/qt_gui/translations/ko_KR.ts
+++ b/src/qt_gui/translations/ko_KR.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Delete DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Hide Cursor Idle Timeout</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>음량</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Failed to create the update script file</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/lt_LT.ts b/src/qt_gui/translations/lt_LT.ts
index 5cf4d0e6b1f..092521fdf8b 100644
--- a/src/qt_gui/translations/lt_LT.ts
+++ b/src/qt_gui/translations/lt_LT.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Delete DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Žymeklio paslėpimo neveikimo laikas</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Garsumas</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Nepavyko sukurti atnaujinimo scenarijaus failo</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/nb.ts b/src/qt_gui/translations/nb.ts
index 4ebe2f0f6b9..cc41573db21 100644
--- a/src/qt_gui/translations/nb.ts
+++ b/src/qt_gui/translations/nb.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Slett DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Skjul musepeker ved inaktivitet</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Volum</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Aldri spilt</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Kunne ikke opprette oppdateringsskriptfilen</translation>
 		</message>
 	</context>
-</TS>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
+</TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/nl.ts b/src/qt_gui/translations/nl.ts
index eb49c83abb1..5cd4a4224b8 100644
--- a/src/qt_gui/translations/nl.ts
+++ b/src/qt_gui/translations/nl.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Delete DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Inactiviteit timeout voor het verbergen van de cursor</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Volume</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Kon het update-scriptbestand niet maken</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/pl_PL.ts b/src/qt_gui/translations/pl_PL.ts
index cb9e7987db5..b85393bb059 100644
--- a/src/qt_gui/translations/pl_PL.ts
+++ b/src/qt_gui/translations/pl_PL.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Delete DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Czas oczekiwania na ukrycie kursora przy bezczynności</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Głośność</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Nie udało się utworzyć pliku skryptu aktualizacji</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/pt_BR.ts b/src/qt_gui/translations/pt_BR.ts
index a668c61d10b..8ab8db09376 100644
--- a/src/qt_gui/translations/pt_BR.ts
+++ b/src/qt_gui/translations/pt_BR.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Deletar DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibilidade...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Atualizar banco de dados</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>Ver status</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Enviar status</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Tempo de Inatividade para Ocultar Cursor</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Volume</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Backend de Áudio</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Nunca jogado</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Falha ao criar o arquivo de script de atualização</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/ro_RO.ts b/src/qt_gui/translations/ro_RO.ts
index ae7e2efcb4a..00547d6bac3 100644
--- a/src/qt_gui/translations/ro_RO.ts
+++ b/src/qt_gui/translations/ro_RO.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Delete DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Timeout pentru ascunderea cursorului inactiv</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Volum</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Nu s-a putut crea fișierul script de actualizare</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/ru_RU.ts b/src/qt_gui/translations/ru_RU.ts
index 8112f9dfd1f..505a05a3e45 100644
--- a/src/qt_gui/translations/ru_RU.ts
+++ b/src/qt_gui/translations/ru_RU.ts
@@ -572,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Время скрытия курсора при бездействии</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>сек</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -727,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Громкость</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Звуковая Подсистема</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1434,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Вы не играли</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>ч</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>м</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>с</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1593,4 +1618,32 @@
 			<translation>Не удалось создать файл скрипта обновления</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>Б</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>КБ</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>МБ</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>ГБ</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>ТБ</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/sq.ts b/src/qt_gui/translations/sq.ts
index c3280e0ea5a..0c318f4f74a 100644
--- a/src/qt_gui/translations/sq.ts
+++ b/src/qt_gui/translations/sq.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Fshi DLC-në</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Koha për fshehjen e kursorit joaktiv</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Vëllimi i zërit</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Nuk është luajtur kurrë</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Krijimi i skedarit skript të përditësimit dështoi</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
diff --git a/src/qt_gui/translations/tr_TR.ts b/src/qt_gui/translations/tr_TR.ts
index 4d644ecfe1a..2845af462cf 100644
--- a/src/qt_gui/translations/tr_TR.ts
+++ b/src/qt_gui/translations/tr_TR.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Delete DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>İmleç İçin Hareketsizlik Zaman Aşımı</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Ses seviyesi</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Güncelleme betiği dosyası oluşturulamadı</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/uk_UA.ts b/src/qt_gui/translations/uk_UA.ts
index 66cbf2bd9e3..8abfca435f0 100644
--- a/src/qt_gui/translations/uk_UA.ts
+++ b/src/qt_gui/translations/uk_UA.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Видалити DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Тайм-аут приховування курсора при бездіяльності</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Гучність</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Не вдалося створити файл скрипта оновлення</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/vi_VN.ts b/src/qt_gui/translations/vi_VN.ts
index 9441d1697e6..7d0e9a2cd69 100644
--- a/src/qt_gui/translations/vi_VN.ts
+++ b/src/qt_gui/translations/vi_VN.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Delete DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>Thời gian chờ ẩn con trỏ</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>Âm lượng</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>Không thể tạo tệp kịch bản cập nhật</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/zh_CN.ts b/src/qt_gui/translations/zh_CN.ts
index 92071c5b23e..4ceb9131547 100644
--- a/src/qt_gui/translations/zh_CN.ts
+++ b/src/qt_gui/translations/zh_CN.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>删除DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>光标空闲超时隐藏</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>音量</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>无法创建更新脚本文件</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file
diff --git a/src/qt_gui/translations/zh_TW.ts b/src/qt_gui/translations/zh_TW.ts
index be7cd69ec4a..3d27267b629 100644
--- a/src/qt_gui/translations/zh_TW.ts
+++ b/src/qt_gui/translations/zh_TW.ts
@@ -175,6 +175,26 @@
 			<source>Delete DLC</source>
 			<translation>Delete DLC</translation>
 		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="99"/>
+			<source>Compatibility...</source>
+			<translation>Compatibility...</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="100"/>
+			<source>Update database</source>
+			<translation>Update database</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="101"/>
+			<source>View report</source>
+			<translation>View report</translation>
+		</message>
+		<message>
+			<location filename="../gui_context_menus.h" line="102"/>
+			<source>Submit a report</source>
+			<translation>Submit a report</translation>
+		</message>
 		<message>
 			<location filename="../gui_context_menus.h" line="195"/>
 			<source>Shortcut creation</source>
@@ -552,6 +572,11 @@
 			<source>Hide Cursor Idle Timeout</source>
 			<translation>游標空閒超時隱藏</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui" line="816"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../settings_dialog.ui" line="767"/>
 			<source>Controller</source>
@@ -707,6 +732,11 @@
 			<source>Volume</source>
 			<translation>音量</translation>
 		</message>
+		<message>
+			<location filename="../settings_dialog.ui"/>
+			<source>Audio Backend</source>
+			<translation>Audio Backend</translation>
+		</message>
 	</context>
 	<context>
 		<name>MainWindow</name>
@@ -1414,6 +1444,21 @@
 			<source>Never Played</source>
 			<translation>Never Played</translation>
 		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>h</source>
+			<translation>h</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>m</source>
+			<translation>m</translation>
+		</message>
+		<message>
+			<location filename="../game_list_frame.cpp"/>
+			<source>s</source>
+			<translation>s</translation>
+		</message>
 		<message>
 			<location filename="../game_list_frame.cpp"/>
 			<source>Compatibility is untested</source>
@@ -1573,4 +1618,32 @@
 			<translation>無法創建更新腳本文件</translation>
 		</message>
 	</context>
+	<context>
+		<name>GameListUtils</name>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>B</source>
+			<translation>B</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>KB</source>
+			<translation>KB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>MB</source>
+			<translation>MB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>GB</source>
+			<translation>GB</translation>
+		</message>
+		<message>
+			<location filename="../game_list_utils.h" line="34"/>
+			<source>TB</source>
+			<translation>TB</translation>
+		</message>		
+	</context>
 </TS>
\ No newline at end of file

From 3218c36b22335e69d558a724627f9876ac70f7b7 Mon Sep 17 00:00:00 2001
From: georgemoralis <giorgosmrls@gmail.com>
Date: Fri, 27 Dec 2024 23:03:03 +0200
Subject: [PATCH 6/6] knack fixes by niko (#1933)

---
 src/core/libraries/ajm/ajm_batch.h                         | 1 +
 src/shader_recompiler/backend/spirv/emit_spirv.cpp         | 1 +
 src/shader_recompiler/backend/spirv/spirv_emit_context.cpp | 1 +
 3 files changed, 3 insertions(+)

diff --git a/src/core/libraries/ajm/ajm_batch.h b/src/core/libraries/ajm/ajm_batch.h
index 65110ee7354..3c586b77316 100644
--- a/src/core/libraries/ajm/ajm_batch.h
+++ b/src/core/libraries/ajm/ajm_batch.h
@@ -12,6 +12,7 @@
 #include <atomic>
 #include <limits>
 #include <memory>
+#include <optional>
 #include <semaphore>
 #include <span>
 #include <vector>
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
index 0ce9eea7cba..900d40472e9 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
@@ -24,6 +24,7 @@ static constexpr spv::ExecutionMode GetInputPrimitiveType(AmdGpu::PrimitiveType
     case AmdGpu::PrimitiveType::PointList:
         return spv::ExecutionMode::InputPoints;
     case AmdGpu::PrimitiveType::LineList:
+    case AmdGpu::PrimitiveType::LineStrip:
         return spv::ExecutionMode::InputLines;
     case AmdGpu::PrimitiveType::TriangleList:
     case AmdGpu::PrimitiveType::TriangleStrip:
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
index d8bafccd990..281c487affa 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
@@ -43,6 +43,7 @@ static constexpr u32 NumVertices(AmdGpu::PrimitiveType type) {
     case AmdGpu::PrimitiveType::PointList:
         return 1u;
     case AmdGpu::PrimitiveType::LineList:
+    case AmdGpu::PrimitiveType::LineStrip:
         return 2u;
     case AmdGpu::PrimitiveType::TriangleList:
     case AmdGpu::PrimitiveType::TriangleStrip: