mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 14:20:42 -07:00
cfg: asio driver selector must list both 32-bit and 64-bit drivers (#734)
## Link to GitHub Issue or related Pull Request, if one exists #730 ## Description of change spicecfg is a 32-bit application. When it uses the ASIO SDK it only saw the 32-bit drivers. There are some ASIO drivers that have different names under 32-bit and 64-bit (Xonar AE is one of them)... so we have to manually scan the registry and surface both the WOW32 and WOW64 nodes. ## Testing <img width="329" height="309" alt="image" src="https://github.com/user-attachments/assets/7abecf76-6835-4df5-8c2e-e7b425130f4c" /> Checked both 32-bit and 64-bit configurator, identical results.
This commit is contained in:
@@ -494,6 +494,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
||||
# hooks
|
||||
hooks/audio/acm.cpp
|
||||
hooks/audio/audio.cpp
|
||||
hooks/audio/asio_driver_scan.cpp
|
||||
hooks/audio/asio_proxy.cpp
|
||||
hooks/audio/buffer.cpp
|
||||
hooks/audio/mme.cpp
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "asio_driver_scan.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "util/utils.h"
|
||||
|
||||
namespace hooks::audio {
|
||||
|
||||
static constexpr char ASIO_REG_PATH[] = "software\\asio";
|
||||
static constexpr char ASIO_REG_DESC[] = "description";
|
||||
|
||||
// enumerate a single registry view, appending to entries while merging
|
||||
// duplicates discovered in another view. Drivers are matched by name (not
|
||||
// CLSID): the game's ASIO loader selects drivers by name, and some vendors
|
||||
// register the same CLSID under different 32-bit/64-bit names (e.g. "XONAR
|
||||
// SOUND CARD" vs "XONAR SOUND CARD(64)"), which are distinct user choices.
|
||||
static void scan_view(
|
||||
REGSAM wow64_flag,
|
||||
bool is_64bit,
|
||||
std::vector<AsioDriverScanEntry> &entries) {
|
||||
|
||||
HKEY hkEnum = nullptr;
|
||||
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, ASIO_REG_PATH, 0,
|
||||
KEY_READ | wow64_flag, &hkEnum) != ERROR_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
char key_name[256];
|
||||
for (DWORD index = 0;
|
||||
RegEnumKeyA(hkEnum, index, key_name, sizeof(key_name)) == ERROR_SUCCESS;
|
||||
index++) {
|
||||
|
||||
// read description (display name), fall back to the key name
|
||||
char desc[256] = { 0 };
|
||||
DWORD size = sizeof(desc);
|
||||
std::string name = key_name;
|
||||
if (RegGetValueA(hkEnum,
|
||||
key_name,
|
||||
ASIO_REG_DESC,
|
||||
RRF_RT_REG_SZ | wow64_flag,
|
||||
nullptr,
|
||||
desc,
|
||||
&size) == ERROR_SUCCESS && desc[0]) {
|
||||
name = desc;
|
||||
}
|
||||
|
||||
// merge with an existing entry from the other view (match by name)
|
||||
const std::string name_lower = strtolower(name);
|
||||
auto it = std::find_if(entries.begin(), entries.end(), [&](const auto &e) {
|
||||
return strtolower(e.name) == name_lower;
|
||||
});
|
||||
if (it == entries.end()) {
|
||||
entries.push_back({ name });
|
||||
it = entries.end() - 1;
|
||||
}
|
||||
it->found_32bit |= !is_64bit;
|
||||
it->found_64bit |= is_64bit;
|
||||
}
|
||||
|
||||
RegCloseKey(hkEnum);
|
||||
}
|
||||
|
||||
std::vector<AsioDriverScanEntry> scan_asio_drivers() {
|
||||
std::vector<AsioDriverScanEntry> entries;
|
||||
|
||||
// 64-bit view first so it wins ordering when present in both
|
||||
scan_view(KEY_WOW64_64KEY, true, entries);
|
||||
scan_view(KEY_WOW64_32KEY, false, entries);
|
||||
|
||||
return entries;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace hooks::audio {
|
||||
|
||||
struct AsioDriverScanEntry {
|
||||
std::string name;
|
||||
bool found_32bit = false;
|
||||
bool found_64bit = false;
|
||||
};
|
||||
|
||||
std::vector<AsioDriverScanEntry> scan_asio_drivers();
|
||||
}
|
||||
@@ -12,9 +12,9 @@
|
||||
#include "build/resource.h"
|
||||
#include "cfg/config.h"
|
||||
#include "cfg/configurator.h"
|
||||
#include "external/asio/asiolist.h"
|
||||
#include "external/imgui/imgui_internal.h"
|
||||
#include "external/imgui/misc/cpp/imgui_stdlib.h"
|
||||
#include "hooks/audio/asio_driver_scan.h"
|
||||
#include "games/io.h"
|
||||
#include "games/sdvx/sdvx.h"
|
||||
#include "games/popn/popn.h"
|
||||
@@ -63,7 +63,7 @@ namespace overlay::windows {
|
||||
constexpr ImVec4 TEXT_COLOR_RED(1.f, 0.f, 0.f, 1.f);
|
||||
constexpr uint32_t OPTION_INPUT_TEXT_WIDTH = 512;
|
||||
|
||||
std::unique_ptr<AsioDriverList> asio_driver_list;
|
||||
std::optional<std::vector<hooks::audio::AsioDriverScanEntry>> asio_driver_list;
|
||||
|
||||
Config::Config(overlay::SpiceOverlay *overlay) : Window(overlay) {
|
||||
this->title = "Configuration";
|
||||
@@ -4426,30 +4426,24 @@ namespace overlay::windows {
|
||||
void Config::build_option_value_picker(Option& option) {
|
||||
auto &definition = option.get_definition();
|
||||
if (definition.picker == OptionPickerType::AsioDriver) {
|
||||
if (asio_driver_list == nullptr) {
|
||||
asio_driver_list = std::make_unique<AsioDriverList>();
|
||||
if (!asio_driver_list.has_value()) {
|
||||
asio_driver_list = hooks::audio::scan_asio_drivers();
|
||||
}
|
||||
|
||||
ImGui::TextUnformatted("If your ASIO driver is not shown here, close this");
|
||||
ImGui::TextUnformatted("popup and enter the driver name manually.");
|
||||
ImGui::SameLine();
|
||||
ImGui::HelpMarker(
|
||||
"This list is populated by scanning the registry for ASIO drivers.\n\n"
|
||||
"If your driver is not showing up, it may be because it is not properly registered in the system.\n\n"
|
||||
"For 64-bit games, check in HKLM\\SOFTWARE\\ASIO\\.\n\n"
|
||||
"For 32-bit games on 64-bit Windows, check in HKLM\\SOFTWARE\\WOW6432Node\\ASIO\\.\n\n"
|
||||
"spicecfg runs in 32-bit, so it may not see 64-bit-only drivers.");
|
||||
|
||||
ImGui::TextUnformatted("");
|
||||
if (asio_driver_list->driver_list.empty()) {
|
||||
if (asio_driver_list->empty()) {
|
||||
ImGui::TextUnformatted("No ASIO drivers found.");
|
||||
} else {
|
||||
ImGui::TextUnformatted("Pick from ASIO drivers:");
|
||||
ImGui::SetNextItemWidth(300.f);
|
||||
if (ImGui::BeginListBox("##asiodrivers")) {
|
||||
for (const auto &driver : asio_driver_list->driver_list) {
|
||||
const bool is_selected = option.value == std::string(driver.name);
|
||||
if (ImGui::Selectable(fmt::format("[{}] {}", driver.id, driver.name).c_str(), is_selected)) {
|
||||
for (const auto &driver : *asio_driver_list) {
|
||||
const bool is_selected = option.value == driver.name;
|
||||
const char *arch = (driver.found_32bit && driver.found_64bit)
|
||||
? "32/64-bit"
|
||||
: (driver.found_64bit ? "64-bit" : "32-bit");
|
||||
if (ImGui::Selectable(
|
||||
fmt::format("{} ({})", driver.name, arch).c_str(),
|
||||
is_selected)) {
|
||||
option.value = driver.name;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user