diff --git a/docs/controls.md b/docs/controls.md index 4b4417c8..08b5f6d3 100644 --- a/docs/controls.md +++ b/docs/controls.md @@ -147,7 +147,7 @@ The game makes its vibration for linear actuators: per side a low and a high ban | A left and a right Joy-Con as one gamepad | to the two Joy-Con's HID devices directly (`runtime/input_hd_pair.c`), as SDL takes no rumble data for the combined gamepad | Bluetooth | | Anything else, the Switch 2 controllers included | the motors, as with `rumble_hd = 0` | | -The log says which it is when a gamepad is taken: `input: HD rumble available for this gamepad: a Pro Controller, through SDL (rumble_hd = 1)`, or `not available` with the reason; the row on the Controls tab is greyed out for a gamepad that cannot take it. With `rumble_hd = 0` nothing is written to the controller and the line says that its driver is asked once the setting is on. The first report a gamepad gets is logged with its bytes (`input: HD rumble: first report written (left ..., right ...)`); a report the controller or its driver refuses is logged too, and the gamepad then rumbles through its motors again. Frequencies are clamped to what the actuators take (41 to 626 Hz in the low band, 82 to 1253 Hz in the high band) and amplitudes to 0..1, the actuators' safe maximum. `rumble_strength` scales the amplitude (100 is the game's own; the default 130 is louder), `rumble_curve` does not apply, and `rumble = 0` silences this path too. A report is written at most every 15 ms (`rumble_hd_ms`, 5 to 50: raise it if a Bluetooth controller stutters or disconnects with HD rumble on), with the newest value only; a value that holds is written again every 30 ms, and the neutral value goes out when the game stops sending for 250 ms, when another gamepad takes over, when the setting is turned off and when the game exits. While HD rumble is on the game makes no dual-motor rumble call for that gamepad. A DualShock 3 on the direct reader keeps its motors either way. +The log says which it is when a gamepad is taken: `input: HD rumble available for this gamepad: a Pro Controller, through SDL (rumble_hd = 1)`, or `not available` with the reason; the row on the Controls tab is greyed out for a gamepad that cannot take it. With `rumble_hd = 0` nothing is written to the controller and the line says that its driver is asked once the setting is on. The first report a gamepad gets is logged with its bytes (`input: HD rumble: first report written (left ..., right ...)`); a report the controller or its driver refuses is logged too, and the gamepad then rumbles through its motors again. Frequencies are clamped to what the actuators take (41 to 626 Hz in the low band, 82 to 1253 Hz in the high band) and amplitudes to 0..1, the actuators' safe maximum. `rumble_strength` scales the amplitude (its default, 130, is the game's own: the default is above 100 for the motors' sake, and this path divides by it), `rumble_curve` does not apply, and `rumble = 0` silences this path too. A report is written at most every 15 ms (`rumble_hd_ms`, 5 to 50: raise it if a Bluetooth controller stutters or disconnects with HD rumble on), with the newest value only; a value that holds is written again every 30 ms, and the neutral value goes out when the game stops sending for 250 ms, when another gamepad takes over, when the setting is turned off and when the game exits. While HD rumble is on the game makes no dual-motor rumble call for that gamepad. A DualShock 3 on the direct reader keeps its motors either way. ## Nintendo Switch 2 controllers diff --git a/nx2navi.ini.example b/nx2navi.ini.example index faa5a70b..93e17789 100644 --- a/nx2navi.ini.example +++ b/nx2navi.ini.example @@ -784,8 +784,8 @@ # rumble_triggers = 0 # HD rumble for a Switch Pro Controller, a Joy-Con or a pair of them: 1 sends the game's vibration to the controller as # the game makes it, each side's low and high band with its own frequency and amplitude, in place of two motor -# strengths. rumble_strength still scales the amplitude (100 = exactly the game's; the controller's safe maximum is -# never passed) and rumble_curve does not apply. 0 (default), and every other gamepad: the motors, as before. Changes +# strengths. rumble_strength still scales the amplitude (its default, 130, is exactly the game's; the controller's +# safe maximum is never passed) and rumble_curve does not apply. 0 (default), and every other gamepad: the motors, as before. Changes # while the game runs take effect at once. rumble_hd_ms is the shortest time between two rumble reports in # milliseconds (5 to 50, default 15): raise it if a controller on Bluetooth stutters or disconnects with HD rumble on. # rumble_hd = 0 diff --git a/runtime/ov_input.c b/runtime/ov_input.c index 582cb2e2..16340ec8 100644 --- a/runtime/ov_input.c +++ b/runtime/ov_input.c @@ -193,7 +193,8 @@ static void once(volatile int32_t *flag, const char *fmt, uint32_t v) { // default 0.6). HD rumble is strong at low amplitude, an ERM motor hardly turns there, so weak values are lifted by the // curve (0.1 -> 0.25) and the strength scales the result (saturating at 65535; 0.66 and up reach full drive at 130 %). // Both are live settings (the menu): read again whenever cfg_version changes. -static float rumble_strength = 1.3f, rumble_curve = 0.6f; +#define RUMBLE_STRENGTH_DEFAULT 1.3f // cfg.c RUMBLE_STRENGTH's default, as a factor +static float rumble_strength = RUMBLE_STRENGTH_DEFAULT, rumble_curve = 0.6f; static volatile int32_t rumble_cfg_logged; static unsigned rumble_cfg_seen = ~0u; static float cfg_float(const char *name, float lo, float hi) { @@ -300,7 +301,9 @@ static float light_share(float f) { return f > 160 ? (f < 320 ? log2f(f / 160) : // Switch HD rumble as it is, for a gamepad whose actuators take it (input.h input_rumble_hd_on; NX2NAVI_RUMBLE_HD): // each side's newest value goes on with both bands' frequency and amplitude, the amplitude scaled by the rumble -// strength alone (100 % = as the game sent it; the curve is for motors). A side the game has not updated for 250 ms, +// strength over its default alone: the default strength is above 100 % to make up for what two motors lose, and an +// actuator that plays the value itself needs none of that, so at the default it gets the game's amplitude exactly and +// the setting makes it weaker or stronger from there (the curve is for motors). A side the game has not updated for 250 ms, // or any side while vibration is not permitted, is at rest. input.c writes the reports and no longer drives that // gamepad's motors, so rumble_update's own call below reaches only the DualShock 3 reader then. Under vib_lock. static void hd_update(uint64_t now) { @@ -311,7 +314,7 @@ static void hd_update(uint64_t now) { v[s] = (RumbleHdValue){vib_last[s].amp_low, vib_last[s].freq_low, vib_last[s].amp_high, vib_last[s].freq_high}; live[s] = vib_allowed && vib_at[s] && now - vib_at[s] <= RUMBLE_STALE_NS; } - input_rumble_hd(v, live, rumble_strength); + input_rumble_hd(v, live, rumble_strength / RUMBLE_STRENGTH_DEFAULT); } // Switch HD rumble -> SDL_RumbleGamepad. Each side's two bands split by frequency between the heavy (low) and the light diff --git a/runtime/ui_text.c b/runtime/ui_text.c index 881504a9..789e35d3 100644 --- a/runtime/ui_text.c +++ b/runtime/ui_text.c @@ -324,7 +324,7 @@ static const char *const text_en[UI_TEXT_COUNT] = { [UI_MENU_RUMBLE_TRIGGERS_DESC] = "Also vibrates the triggers on Xbox controllers.", [UI_MENU_RUMBLE_HD] = "HD vibration (Switch)", [UI_MENU_RUMBLE_HD_DESC] = "Sends the game's detailed vibration to a Switch Pro Controller or Joy-Con as it is. " - "The vibration strength still applies: 100 % is the game's own.", + "The vibration strength still applies: its default is the game's own.", [UI_MENU_RUMBLE_HD_NEEDS] = "Needs a Switch Pro Controller or Joy-Con", [UI_MENU_PAD_LAYOUT] = "Button layout", [UI_MENU_PAD_LAYOUT_DESC] = "Sets which button acts as A. Nintendo: by position, A right, B bottom, X top, Y " @@ -1027,7 +1027,7 @@ static const char *const text_ru[UI_TEXT_COUNT] = { [UI_MENU_RUMBLE_TRIGGERS_DESC] = "Вибрация также на курках контроллера Xbox.", [UI_MENU_RUMBLE_HD] = "HD-вибрация (Switch)", [UI_MENU_RUMBLE_HD_DESC] = "Передаёт детальную вибрацию игры на Switch Pro Controller или Joy-Con без изменений. " - "Сила вибрации по-прежнему действует: 100 % — как в игре.", + "Сила вибрации по-прежнему действует: значение по умолчанию — как в игре.", [UI_MENU_RUMBLE_HD_NEEDS] = "Нужен Switch Pro Controller или Joy-Con", [UI_MENU_PAD_LAYOUT] = "Раскладка кнопок", [UI_MENU_PAD_LAYOUT_DESC] = "Какая кнопка работает как A. Nintendo: по положению, A справа, B снизу, X сверху, " @@ -1607,7 +1607,7 @@ static const char *const text_pt_br[UI_TEXT_COUNT] = { [UI_MENU_RUMBLE_TRIGGERS_DESC] = "Também vibra os gatilhos do controle Xbox.", [UI_MENU_RUMBLE_HD] = "Vibração HD (Switch)", [UI_MENU_RUMBLE_HD_DESC] = "Envia a vibração detalhada do jogo a um Pro Controller do Switch ou Joy-Con como ela " - "é. A intensidade da vibração continua valendo: 100 % é a do jogo.", + "é. A intensidade da vibração continua valendo: o valor padrão é a do jogo.", [UI_MENU_RUMBLE_HD_NEEDS] = "Requer um Pro Controller do Switch ou Joy-Con", [UI_MENU_PAD_LAYOUT] = "Layout dos botões", [UI_MENU_PAD_LAYOUT_DESC] = "Define qual botão funciona como A. Nintendo: pela posição, A à direita, B embaixo, " @@ -2337,7 +2337,7 @@ static const char *const text_zh_hans[UI_TEXT_COUNT] = { [UI_MENU_RUMBLE_TRIGGERS] = "扳机振动(Xbox)", [UI_MENU_RUMBLE_TRIGGERS_DESC] = "同时震动 Xbox 手柄的扳机。", [UI_MENU_RUMBLE_HD] = "HD 振动(Switch)", - [UI_MENU_RUMBLE_HD_DESC] = "将游戏的细腻振动原样发送到 Switch Pro 手柄或 Joy-Con。振动强度仍然有效:100% 即游戏原本的强度。", + [UI_MENU_RUMBLE_HD_DESC] = "将游戏的细腻振动原样发送到 Switch Pro 手柄或 Joy-Con。振动强度仍然有效:默认值即游戏原本的强度。", [UI_MENU_RUMBLE_HD_NEEDS] = "需要 Switch Pro 手柄或 Joy-Con", [UI_MENU_PAD_LAYOUT] = "按键布局", [UI_MENU_PAD_LAYOUT_DESC] = "设置哪个按键作为 A 键。Nintendo:按位置,A 在右、B 在下、X 在上、Y 在左。Xbox 和 PlayStation:"