iidx: delay logic for iidx tt (#669)

## Link to GitHub Issue or related Pull Request, if one exists
Re-implements fix for #181 as it was removed by #668

## Description of change
Add two options to add artificial delay to turntable input. These
operate directly on the input logic (`get_tt`) which is called by I/O
emulation code.

Functionally, it's **identical** to the `Delay (experimental)` option we
had in the analog tab, just moved to Options tab.

## Testing
64 bit tdj: ok
64 bit ldj bi2a: ok
32 bit ldj ezusb: ok

Worth noting that TDJ bi2x_hook polls at 120Hz, bi2a at ~500Hz, and
ezusb at ~170Hz
This commit is contained in:
bicarus
2026-05-02 02:17:51 -07:00
committed by GitHub
parent c5a4e954f9
commit 79a3e32d5d
5 changed files with 52 additions and 1 deletions
+22 -1
View File
@@ -67,6 +67,8 @@ namespace games::iidx {
std::optional<std::string> SOUND_OUTPUT_DEVICE = std::nullopt; std::optional<std::string> SOUND_OUTPUT_DEVICE = std::nullopt;
std::optional<std::string> SOUND_OUTPUT_DEVICE_IN_EFFECT = std::nullopt; std::optional<std::string> SOUND_OUTPUT_DEVICE_IN_EFFECT = std::nullopt;
std::optional<std::string> ASIO_DRIVER = std::nullopt; std::optional<std::string> ASIO_DRIVER = std::nullopt;
uint32_t TT_DELAY_P1 = 0;
uint32_t TT_DELAY_P2 = 0;
uint8_t DIGITAL_TT_SENS = 4; uint8_t DIGITAL_TT_SENS = 4;
std::optional<std::string> SUBSCREEN_OVERLAY_SIZE = std::nullopt; std::optional<std::string> SUBSCREEN_OVERLAY_SIZE = std::nullopt;
std::optional<std::string> SCREEN_MODE = std::nullopt; std::optional<std::string> SCREEN_MODE = std::nullopt;
@@ -781,7 +783,26 @@ namespace games::iidx {
} }
// return higher 8 bit // return higher 8 bit
return (uint8_t) (ret_value >> 2); uint8_t result = (uint8_t) (ret_value >> 2);
// delay
if ((player == 0 && TT_DELAY_P1 > 0) ||
(player == 1 && TT_DELAY_P2 > 0)) {
static std::queue<uint8_t> delay_queue[2];
auto &queue = delay_queue[player];
const auto max_size =
static_cast<size_t>((player == 0) ? TT_DELAY_P1 : TT_DELAY_P2) + 1;
queue.push(result);
while (queue.size() > max_size) {
queue.pop();
}
result = queue.front();
}
return result;
} }
unsigned char get_slider(uint8_t slider) { unsigned char get_slider(uint8_t slider) {
+2
View File
@@ -31,6 +31,8 @@ namespace games::iidx {
extern bool NATIVE_TOUCH; extern bool NATIVE_TOUCH;
extern std::optional<std::string> SOUND_OUTPUT_DEVICE; extern std::optional<std::string> SOUND_OUTPUT_DEVICE;
extern std::optional<std::string> ASIO_DRIVER; extern std::optional<std::string> ASIO_DRIVER;
extern uint32_t TT_DELAY_P1;
extern uint32_t TT_DELAY_P2;
extern uint8_t DIGITAL_TT_SENS; extern uint8_t DIGITAL_TT_SENS;
extern std::optional<std::string> SUBSCREEN_OVERLAY_SIZE; extern std::optional<std::string> SUBSCREEN_OVERLAY_SIZE;
extern std::optional<std::string> SCREEN_MODE; extern std::optional<std::string> SCREEN_MODE;
+6
View File
@@ -518,6 +518,12 @@ int main_implementation(int argc, char *argv[]) {
if (options[launcher::Options::IIDXTDJMode].value_bool()) { if (options[launcher::Options::IIDXTDJMode].value_bool()) {
games::iidx::TDJ_MODE = true; games::iidx::TDJ_MODE = true;
} }
if (options[launcher::Options::IIDXTTDelayP1].is_active()) {
games::iidx::TT_DELAY_P1 = options[launcher::Options::IIDXTTDelayP1].value_uint32();
}
if (options[launcher::Options::IIDXTTDelayP2].is_active()) {
games::iidx::TT_DELAY_P2 = options[launcher::Options::IIDXTTDelayP2].value_uint32();
}
if (options[launcher::Options::spice2x_IIDXDigitalTTSensitivity].is_active()) { if (options[launcher::Options::spice2x_IIDXDigitalTTSensitivity].is_active()) {
games::iidx::DIGITAL_TT_SENS = (uint8_t) games::iidx::DIGITAL_TT_SENS = (uint8_t)
options[launcher::Options::spice2x_IIDXDigitalTTSensitivity].value_uint32(); options[launcher::Options::spice2x_IIDXDigitalTTSensitivity].value_uint32();
+20
View File
@@ -655,6 +655,26 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.game_name = "Beatmania IIDX", .game_name = "Beatmania IIDX",
.category = "Game Options", .category = "Game Options",
}, },
{
// IIDXTTDelayP1
.title = "IIDX TT Delay Frames (Player 1)",
.name = "iidxttdelayp1",
.desc = "Delays turntable input by number of poll frames. Heavily dependent on what I/O emulation is in use! "
"As usual, changing any option requires a restart. Default: 0 (no delay).",
.type = OptionType::Integer,
.game_name = "Beatmania IIDX",
.category = "Game Options (Advanced)",
},
{
// IIDXTTDelayP2
.title = "IIDX TT Delay Frames (Player 2)",
.name = "iidxttdelayp2",
.desc = "Delays turntable input by number of poll frames. Heavily dependent on what I/O emulation is in use! "
"As usual, changing any option requires a restart. Default: 0 (no delay).",
.type = OptionType::Integer,
.game_name = "Beatmania IIDX",
.category = "Game Options (Advanced)",
},
{ {
// spice2x_IIDXDigitalTTSensitivity // spice2x_IIDXDigitalTTSensitivity
.title = "IIDX Digital TT Sensitivity", .title = "IIDX Digital TT Sensitivity",
+2
View File
@@ -69,6 +69,8 @@ namespace launcher {
IIDXAsioDriver, IIDXAsioDriver,
IIDXBIO2FW, IIDXBIO2FW,
IIDXTDJMode, IIDXTDJMode,
IIDXTTDelayP1,
IIDXTTDelayP2,
spice2x_IIDXDigitalTTSensitivity, spice2x_IIDXDigitalTTSensitivity,
IIDXDigitalTTSocd, IIDXDigitalTTSocd,
spice2x_IIDXLDJForce720p, spice2x_IIDXLDJForce720p,