Skip to content

Commit c93d3b1

Browse files
committed
Allow axis to control volume actions
1 parent c2d7f66 commit c93d3b1

9 files changed

Lines changed: 214 additions & 83 deletions

File tree

data/locale/en-US.ini

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ JoypadToOBS.Field.Multiplier="Scale"
1717
JoypadToOBS.Field.UseCurrentScene="Use current scene"
1818
JoypadToOBS.Field.AllowAboveDb="Allow above 0 dB"
1919
JoypadToOBS.Field.AxisValue="Axis value"
20-
JoypadToOBS.Field.AxisThreshold="Axis threshold"
20+
JoypadToOBS.Field.AxisThreshold="Axis deadzone"
21+
JoypadToOBS.Field.AxisMinPerSecond="Min triggers per second"
22+
JoypadToOBS.Field.AxisMaxPerSecond="Max triggers per second"
23+
JoypadToOBS.Field.AxisActivationMin="Min activation"
24+
JoypadToOBS.Field.AxisActivationMax="Max activation"
2125
JoypadToOBS.Field.AxisBothDirections="Use both directions (+/-)"
2226
JoypadToOBS.Field.AxisMinValue="Axis min"
2327
JoypadToOBS.Field.AxisMaxValue="Axis max"

data/locale/pt-BR.ini

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ JoypadToOBS.Field.Multiplier="Escala"
1717
JoypadToOBS.Field.UseCurrentScene="Usar cena atual"
1818
JoypadToOBS.Field.AllowAboveDb="Permitir acima de 0 dB"
1919
JoypadToOBS.Field.AxisValue="Valor do eixo"
20-
JoypadToOBS.Field.AxisThreshold="Limiar do eixo"
20+
JoypadToOBS.Field.AxisThreshold="Zona morta do eixo"
21+
JoypadToOBS.Field.AxisMinPerSecond="Acionamento mínimo por segundo"
22+
JoypadToOBS.Field.AxisMaxPerSecond="Acionamento máximo por segundo"
23+
JoypadToOBS.Field.AxisActivationMin="Acionamento mínimo"
24+
JoypadToOBS.Field.AxisActivationMax="Acionamento máximo"
2125
JoypadToOBS.Field.AxisBothDirections="Usar ambas direções (+/-)"
2226
JoypadToOBS.Field.AxisMinValue="Mínimo do eixo"
2327
JoypadToOBS.Field.AxisMaxValue="Máximo do eixo"

data/locale/pt-PT.ini

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ JoypadToOBS.Field.Multiplier="Escala"
1717
JoypadToOBS.Field.UseCurrentScene="Usar cena atual"
1818
JoypadToOBS.Field.AllowAboveDb="Permitir acima de 0 dB"
1919
JoypadToOBS.Field.AxisValue="Valor do eixo"
20-
JoypadToOBS.Field.AxisThreshold="Limiar do eixo"
20+
JoypadToOBS.Field.AxisThreshold="Zona morta do eixo"
21+
JoypadToOBS.Field.AxisMinPerSecond="Acionamento mínimo por segundo"
22+
JoypadToOBS.Field.AxisMaxPerSecond="Acionamento máximo por segundo"
23+
JoypadToOBS.Field.AxisActivationMin="Acionamento mínimo"
24+
JoypadToOBS.Field.AxisActivationMax="Acionamento máximo"
2125
JoypadToOBS.Field.AxisBothDirections="Usar ambas direções (+/-)"
2226
JoypadToOBS.Field.AxisMinValue="Mínimo do eixo"
2327
JoypadToOBS.Field.AxisMaxValue="Máximo do eixo"

src/joypad-actions.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -208,22 +208,22 @@ void JoypadActionEngine::Execute(const JoypadBinding &binding)
208208
if (!source) {
209209
return;
210210
}
211-
float current_mul = obs_source_get_volume(source);
212-
float next_mul = current_mul + (float)binding.volume_value;
213-
if (next_mul < 0.0f) {
214-
next_mul = 0.0f;
211+
const float current_mul = obs_source_get_volume(source);
212+
float current_db = mul_to_db(current_mul);
213+
if (current_db < kMinDb) {
214+
current_db = kMinDb;
215215
}
216-
if (!binding.allow_above_unity && next_mul > 1.0f) {
217-
next_mul = 1.0f;
216+
float next_db = current_db + (float)binding.volume_value;
217+
if (!binding.allow_above_unity && next_db > 0.0f) {
218+
next_db = 0.0f;
218219
}
219-
float min_mul = db_to_mul(kMinDb);
220-
float max_mul = db_to_mul(kMaxDb);
221-
if (next_mul < min_mul) {
222-
next_mul = min_mul;
220+
if (next_db < kMinDb) {
221+
next_db = kMinDb;
223222
}
224-
if (next_mul > max_mul) {
225-
next_mul = max_mul;
223+
if (next_db > kMaxDb) {
224+
next_db = kMaxDb;
226225
}
226+
const float next_mul = db_to_mul(next_db);
227227
if (std::fabs(current_mul - next_mul) > kVolumeEpsilon) {
228228
obs_source_set_volume(source, next_mul);
229229
}

src/joypad-config.cpp

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,25 @@ static void load_binding_from_data(JoypadBinding &binding, obs_data_t *data)
132132
binding.axis_threshold = obs_data_get_double(data, "axis_threshold");
133133
bool axis_threshold_set = obs_data_get_bool(data, "axis_threshold_set");
134134
if (!axis_threshold_set) {
135-
binding.axis_threshold = 0.5;
135+
binding.axis_threshold = 0.10;
136+
}
137+
binding.axis_min_per_second = obs_data_get_double(data, "axis_min_per_second");
138+
if (!obs_data_has_user_value(data, "axis_min_per_second")) {
139+
// Backward compatibility with older configs.
140+
double legacy_min = obs_data_get_double(data, "axis_activation_min");
141+
binding.axis_min_per_second = legacy_min > 0.0 ? legacy_min * 10.0 : 2.5;
142+
}
143+
binding.axis_max_per_second = obs_data_get_double(data, "axis_max_per_second");
144+
if (!obs_data_has_user_value(data, "axis_max_per_second")) {
145+
// Backward compatibility with older configs.
146+
double legacy_max = obs_data_get_double(data, "axis_activation_max");
147+
binding.axis_max_per_second = legacy_max > 0.0 ? legacy_max * 10.0 : 20.0;
148+
}
149+
binding.axis_threshold = std::clamp(binding.axis_threshold, 0.0, 0.95);
150+
binding.axis_min_per_second = std::clamp(binding.axis_min_per_second, 1.0, 60.0);
151+
binding.axis_max_per_second = std::clamp(binding.axis_max_per_second, 1.0, 60.0);
152+
if (binding.axis_max_per_second < binding.axis_min_per_second) {
153+
binding.axis_max_per_second = binding.axis_min_per_second;
136154
}
137155
binding.axis_interval_ms = (int)obs_data_get_int(data, "axis_interval_ms");
138156
if (binding.axis_interval_ms <= 0) {
@@ -187,6 +205,8 @@ static void save_binding_to_data(const JoypadBinding &binding, obs_data_t *data)
187205
obs_data_set_bool(data, "axis_inverted", binding.axis_inverted);
188206
obs_data_set_double(data, "axis_threshold", binding.axis_threshold);
189207
obs_data_set_bool(data, "axis_threshold_set", true);
208+
obs_data_set_double(data, "axis_min_per_second", binding.axis_min_per_second);
209+
obs_data_set_double(data, "axis_max_per_second", binding.axis_max_per_second);
190210
obs_data_set_int(data, "axis_interval_ms", binding.axis_interval_ms);
191211
obs_data_set_double(data, "axis_min_value", binding.axis_min_value);
192212
obs_data_set_double(data, "axis_max_value", binding.axis_max_value);
@@ -903,8 +923,8 @@ std::vector<JoypadBinding> JoypadConfigStore::FindMatchingBindings(const JoypadE
903923
}
904924
}
905925

906-
const double threshold_on = binding.axis_threshold;
907-
const double threshold_off = binding.axis_threshold * 0.4;
926+
const double threshold_on = std::clamp(binding.axis_threshold, 0.0, 0.95);
927+
const double threshold_off = threshold_on * 0.4;
908928
std::string axis_key = event.device_id + ":" + std::to_string(binding.axis_index) + ":" +
909929
std::to_string((int)binding.axis_direction) + ":" +
910930
(binding.axis_inverted ? "1" : "0");
@@ -924,13 +944,18 @@ std::vector<JoypadBinding> JoypadConfigStore::FindMatchingBindings(const JoypadE
924944
}
925945
if (binding.action == JoypadActionType::AdjustSourceVolume) {
926946
double sign = value >= 0.0 ? 1.0 : -1.0;
927-
double intensity = std::clamp(abs_value, 0.0, 1.0);
928-
binding.volume_value = std::fabs(binding.volume_value) * intensity * sign;
947+
binding.volume_value = std::fabs(binding.volume_value) * sign;
929948
}
930949
const bool is_continuous_axis_action =
931-
(binding.action == JoypadActionType::SetSourceVolumePercent) ||
932-
(binding.action == JoypadActionType::AdjustSourceVolume);
933-
if (!is_continuous_axis_action && binding.axis_interval_ms > 0) {
950+
(binding.action == JoypadActionType::SetSourceVolumePercent);
951+
if (!is_continuous_axis_action) {
952+
const double min_rate = std::clamp(binding.axis_min_per_second, 1.0, 60.0);
953+
const double max_rate = std::clamp(binding.axis_max_per_second, min_rate, 60.0);
954+
double intensity =
955+
std::clamp((abs_value - threshold_on) / (1.0 - threshold_on), 0.0, 1.0);
956+
double rate = min_rate + (max_rate - min_rate) * intensity;
957+
int dynamic_interval_ms = (int)std::round(1000.0 / std::max(rate, 0.001));
958+
dynamic_interval_ms = std::max(dynamic_interval_ms, 1);
934959
std::string interval_key;
935960
if (binding.uid > 0) {
936961
interval_key = std::to_string((long long)binding.uid);
@@ -944,7 +969,7 @@ std::vector<JoypadBinding> JoypadConfigStore::FindMatchingBindings(const JoypadE
944969
const auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
945970
now - it_last->second)
946971
.count();
947-
if (elapsed < binding.axis_interval_ms) {
972+
if (elapsed < dynamic_interval_ms) {
948973
continue;
949974
}
950975
}

src/joypad-config.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,11 @@ struct JoypadBinding {
8282
int button = -1;
8383
JoypadInputType input_type = JoypadInputType::Button;
8484
int axis_index = -1;
85-
JoypadAxisDirection axis_direction = JoypadAxisDirection::Positive;
85+
JoypadAxisDirection axis_direction = JoypadAxisDirection::Both;
8686
bool axis_inverted = false;
87-
double axis_threshold = 0.5;
87+
double axis_threshold = 0.10;
88+
double axis_min_per_second = 2.5;
89+
double axis_max_per_second = 20.0;
8890
int axis_interval_ms = 150;
8991
double axis_min_value = 0.0;
9092
double axis_max_value = 1024.0;

src/joypad-input.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
4848

4949
namespace {
5050
constexpr int kMaxTrackedAxes = 8;
51+
constexpr double kAxisContinuousHoldThreshold = 0.01;
5152

5253
#ifdef _WIN32
5354
struct DiControllerInfo {
@@ -927,13 +928,15 @@ bool JoypadInputManager::BeginLearn(std::function<void(const JoypadEvent &)> han
927928
return false;
928929
}
929930
learn_handler_ = std::move(handler);
931+
learn_active_.store(true, std::memory_order_release);
930932
return true;
931933
}
932934

933935
void JoypadInputManager::CancelLearn()
934936
{
935937
std::lock_guard<std::mutex> lock(handler_mutex_);
936938
learn_handler_ = nullptr;
939+
learn_active_.store(false, std::memory_order_release);
937940
}
938941

939942
void JoypadInputManager::MarkDeviceDisconnected(DeviceState &state)
@@ -1057,7 +1060,9 @@ void JoypadInputManager::PollLoop()
10571060
continue;
10581061
}
10591062
double prev_raw = state.last_axes[i];
1060-
if (std::fabs(raw - prev_raw) < 0.000001) {
1063+
const bool hold_active = std::fabs(normalized) >= kAxisContinuousHoldThreshold;
1064+
const bool learning_active = learn_active_.load(std::memory_order_acquire);
1065+
if (std::fabs(raw - prev_raw) < 0.000001 && (!hold_active || learning_active)) {
10611066
continue;
10621067
}
10631068
if (it != axis_last_trigger_.end() &&
@@ -1132,7 +1137,11 @@ void JoypadInputManager::PollLoop()
11321137
continue;
11331138
}
11341139
double prev = state.last_axes[axis_index];
1135-
if (raw == prev) {
1140+
const bool hold_active = std::fabs(value) >=
1141+
kAxisContinuousHoldThreshold;
1142+
const bool learning_active =
1143+
learn_active_.load(std::memory_order_acquire);
1144+
if (raw == prev && (!hold_active || learning_active)) {
11361145
continue;
11371146
}
11381147
if (it != axis_last_trigger_.end() &&
@@ -1436,7 +1445,11 @@ void JoypadInputManager::PollLoop()
14361445
if (init_only) {
14371446
return;
14381447
}
1439-
if (raw == prev) {
1448+
const bool hold_active = std::fabs(norm) >=
1449+
kAxisContinuousHoldThreshold;
1450+
const bool learning_active =
1451+
self->learn_active_.load(std::memory_order_acquire);
1452+
if (raw == prev && (!hold_active || learning_active)) {
14401453
return;
14411454
}
14421455
if (it != self->axis_last_trigger_.end() &&
@@ -1510,6 +1523,7 @@ void JoypadInputManager::DispatchEvent(const JoypadEvent &event)
15101523
}
15111524
if (learn_handler_) {
15121525
learn_handler_ = nullptr;
1526+
learn_active_.store(false, std::memory_order_release);
15131527
}
15141528
}
15151529

@@ -1543,6 +1557,7 @@ void JoypadInputManager::DispatchAxisAbsolute(const JoypadEvent &event)
15431557
}
15441558
if (learn_handler_) {
15451559
learn_handler_ = nullptr;
1560+
learn_active_.store(false, std::memory_order_release);
15461561
}
15471562
}
15481563
if (learn_handler) {

src/joypad-input.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ class JoypadInputManager {
9393
std::mutex handler_mutex_;
9494
std::function<void(const JoypadEvent &)> on_button_pressed_;
9595
std::function<void(const JoypadEvent &)> learn_handler_;
96+
std::atomic<bool> learn_active_{false};
9697
struct AxisHandlerEntry {
9798
int id = 0;
9899
std::function<void(const JoypadEvent &)> handler;

0 commit comments

Comments
 (0)