Rumble data processing refactor (#591)

* Rumble reimplementation

* Remove white space

* More whitespace

* Remove Update
This commit is contained in:
shukenmg 2020-11-03 16:19:59 +08:00 committed by GitHub
parent 6f5316d462
commit bfdea232cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 34 additions and 56 deletions

View file

@ -13,9 +13,6 @@
<!--Whether the Motion Server is enabled or not. Default: true --> <!--Whether the Motion Server is enabled or not. Default: true -->
<add key="MotionServer" value="true" /> <add key="MotionServer" value="true" />
<!--Rumble motor period in millisec. Lower means more granular vibration, higher is more stable.-->
<!--The response of rumble does not only depend on this setting and it's always high. Default: 300 -->
<add key="RumblePeriod" value="300" />
<!--The controller's HD rumble settings for the low/high frequency rumble. Change to change the pitch of the rumble.--> <!--The controller's HD rumble settings for the low/high frequency rumble. Change to change the pitch of the rumble.-->
<!--Don't set above ~1200. Default: 40 and 120 --> <!--Don't set above ~1200. Default: 40 and 120 -->
<!--To have "stronger" rumble, try setting the low/high to 160/320--> <!--To have "stronger" rumble, try setting the low/high to 160/320-->

View file

@ -123,46 +123,21 @@ namespace BetterJoyForCemu {
private const uint report_len = 49; private const uint report_len = 49;
private struct Rumble { private struct Rumble {
private float h_f, l_f; public Queue<float[]> queue;
public float amp;
public bool controller_informed;
public long end_rumble_time_milliseconds;
public void set_vals(float low_freq, float high_freq, float amplitude, int rumble_duration_ms = 0) { public void set_vals(float low_freq, float high_freq, float amplitude) {
h_f = high_freq; float[] rumbleQueue = new float[] {low_freq, high_freq, amplitude};
amp = amplitude; queue.Enqueue(rumbleQueue);
l_f = low_freq;
if (rumble_duration_ms != 0) {
end_rumble_time_milliseconds = DateTimeOffset.Now.ToUnixTimeMilliseconds() + rumble_duration_ms;
} else {
end_rumble_time_milliseconds = 0;
}
controller_informed = false;
} }
public Rumble(float low_freq, float high_freq, float amplitude, int rumble_duration_ms = 0) { public Rumble(float[] rumble_info) {
h_f = high_freq; queue = new Queue<float[]>();
amp = amplitude; queue.Enqueue(rumble_info);
l_f = low_freq;
if (rumble_duration_ms != 0) {
end_rumble_time_milliseconds = DateTimeOffset.Now.ToUnixTimeMilliseconds() + rumble_duration_ms;
} else {
end_rumble_time_milliseconds = 0;
}
controller_informed = false;
} }
private float clamp(float x, float min, float max) { private float clamp(float x, float min, float max) {
if (x < min) return min; if (x < min) return min;
if (x > max) return max; if (x > max) return max;
return x; return x;
} }
public void Update() {
if (end_rumble_time_milliseconds != 0 && DateTimeOffset.Now.ToUnixTimeMilliseconds() > end_rumble_time_milliseconds) {
controller_informed = false;
end_rumble_time_milliseconds = 0;
amp = 0;
}
}
private byte EncodeAmp(float amp) { private byte EncodeAmp(float amp) {
byte en_amp; byte en_amp;
@ -181,21 +156,22 @@ namespace BetterJoyForCemu {
public byte[] GetData() { public byte[] GetData() {
byte[] rumble_data = new byte[8]; byte[] rumble_data = new byte[8];
float[] queued_data = queue.Dequeue();
if (amp == 0.0f) { if (queued_data[2] == 0.0f) {
rumble_data[0] = 0x0; rumble_data[0] = 0x0;
rumble_data[1] = 0x1; rumble_data[1] = 0x1;
rumble_data[2] = 0x40; rumble_data[2] = 0x40;
rumble_data[3] = 0x40; rumble_data[3] = 0x40;
} else { } else {
l_f = clamp(l_f, 40.875885f, 626.286133f); queued_data[0] = clamp(queued_data[0], 40.875885f, 626.286133f);
h_f = clamp(h_f, 81.75177f, 1252.572266f); queued_data[1] = clamp(queued_data[1], 81.75177f, 1252.572266f);
amp = clamp(amp, 0.0f, 1.0f); queued_data[2] = clamp(queued_data[2], 0.0f, 1.0f);
UInt16 hf = (UInt16)((Math.Round(32f * Math.Log(h_f * 0.1f, 2)) - 0x60) * 4); UInt16 hf = (UInt16)((Math.Round(32f * Math.Log(queued_data[1] * 0.1f, 2)) - 0x60) * 4);
byte lf = (byte)(Math.Round(32f * Math.Log(l_f * 0.1f, 2)) - 0x40); byte lf = (byte)(Math.Round(32f * Math.Log(queued_data[0] * 0.1f, 2)) - 0x40);
byte hf_amp = EncodeAmp(amp); byte hf_amp = EncodeAmp(queued_data[2]);
UInt16 lf_amp = (UInt16)(Math.Round((double)hf_amp) * .5); UInt16 lf_amp = (UInt16)(Math.Round((double)hf_amp) * .5);
byte parity = (byte)(lf_amp % 2); byte parity = (byte)(lf_amp % 2);
@ -243,7 +219,6 @@ namespace BetterJoyForCemu {
ushort ds4_ts = 0; ushort ds4_ts = 0;
ulong lag; ulong lag;
int rumblePeriod = Int32.Parse(ConfigurationManager.AppSettings["RumblePeriod"]);
int lowFreq = Int32.Parse(ConfigurationManager.AppSettings["LowFreqRumble"]); int lowFreq = Int32.Parse(ConfigurationManager.AppSettings["LowFreqRumble"]);
int highFreq = Int32.Parse(ConfigurationManager.AppSettings["HighFreqRumble"]); int highFreq = Int32.Parse(ConfigurationManager.AppSettings["HighFreqRumble"]);
@ -267,7 +242,7 @@ namespace BetterJoyForCemu {
handle = handle_; handle = handle_;
imu_enabled = imu; imu_enabled = imu;
do_localize = localize; do_localize = localize;
rumble_obj = new Rumble(lowFreq, highFreq, 0, 0); rumble_obj = new Rumble(new float[] {lowFreq, highFreq, 0});
for (int i = 0; i < buttons_down_timestamp.Length; i++) for (int i = 0; i < buttons_down_timestamp.Length; i++)
buttons_down_timestamp[i] = -1; buttons_down_timestamp[i] = -1;
filterweight = alpha; filterweight = alpha;
@ -302,17 +277,19 @@ namespace BetterJoyForCemu {
} }
public void ReceiveRumble(Xbox360FeedbackReceivedEventArgs e) { public void ReceiveRumble(Xbox360FeedbackReceivedEventArgs e) {
SetRumble(lowFreq, highFreq, (float)Math.Max(e.LargeMotor, e.SmallMotor) / (float)255, rumblePeriod); DebugPrint("Rumble data Recived: XInput", DebugType.RUMBLE);
SetRumble(lowFreq, highFreq, (float)Math.Max(e.LargeMotor, e.SmallMotor) / (float)255);
if (other != null && other != this) if (other != null && other != this)
other.SetRumble(lowFreq, highFreq, (float)Math.Max(e.LargeMotor, e.SmallMotor) / (float)255, rumblePeriod); other.SetRumble(lowFreq, highFreq, (float)Math.Max(e.LargeMotor, e.SmallMotor) / (float)255);
} }
public void Ds4_FeedbackReceived(DualShock4FeedbackReceivedEventArgs e) { public void Ds4_FeedbackReceived(DualShock4FeedbackReceivedEventArgs e) {
SetRumble(lowFreq, highFreq, (float)Math.Max(e.LargeMotor, e.SmallMotor) / (float)255, rumblePeriod); DebugPrint("Rumble data Recived: DS4", DebugType.RUMBLE);
SetRumble(lowFreq, highFreq, (float)Math.Max(e.LargeMotor, e.SmallMotor) / (float)255);
if (other != null && other != this) if (other != null && other != this)
other.SetRumble(lowFreq, highFreq, (float)Math.Max(e.LargeMotor, e.SmallMotor) / (float)255, rumblePeriod); other.SetRumble(lowFreq, highFreq, (float)Math.Max(e.LargeMotor, e.SmallMotor) / (float)255);
} }
public void DebugPrint(String s, DebugType d) { public void DebugPrint(String s, DebugType d) {
@ -787,10 +764,12 @@ namespace BetterJoyForCemu {
stop_polling = false; stop_polling = false;
int attempts = 0; int attempts = 0;
while (!stop_polling & state > state_.NO_JOYCONS) { while (!stop_polling & state > state_.NO_JOYCONS) {
rumble_obj.Update(); if (rumble_obj.queue.Count > 0) {
if (!rumble_obj.controller_informed) {
SendRumble(rumble_obj.GetData()); SendRumble(rumble_obj.GetData());
rumble_obj.controller_informed = true; // Keep a queue of 15 items, discard oldest item if queue is full.
if (rumble_obj.queue.Count > 15) {
rumble_obj.queue.Dequeue();
}
} }
int a = ReceiveRaw(); int a = ReceiveRaw();
@ -1057,9 +1036,9 @@ namespace BetterJoyForCemu {
return (byte)Math.Max(Byte.MinValue, Math.Min(Byte.MaxValue, 127 - stick_value * Byte.MaxValue)); return (byte)Math.Max(Byte.MinValue, Math.Min(Byte.MaxValue, 127 - stick_value * Byte.MaxValue));
} }
public void SetRumble(float low_freq, float high_freq, float amp, int rumble_duration_ms = 0) { public void SetRumble(float low_freq, float high_freq, float amp) {
if (state <= Joycon.state_.ATTACHED) return; if (state <= Joycon.state_.ATTACHED) return;
rumble_obj.set_vals(low_freq, high_freq, amp, rumble_duration_ms); rumble_obj.set_vals(low_freq, high_freq, amp);
} }
private void SendRumble(byte[] buf) { private void SendRumble(byte[] buf) {

View file

@ -172,7 +172,7 @@ namespace BetterJoyForCemu {
bool showAsXInput = Boolean.Parse(ConfigurationManager.AppSettings["ShowAsXInput"]); bool showAsXInput = Boolean.Parse(ConfigurationManager.AppSettings["ShowAsXInput"]);
bool showAsDS4 = Boolean.Parse(ConfigurationManager.AppSettings["ShowAsDS4"]); bool showAsDS4 = Boolean.Parse(ConfigurationManager.AppSettings["ShowAsDS4"]);
public void locBtnClick(object sender, EventArgs e) { public async void locBtnClickAsync(object sender, EventArgs e) {
Button bb = sender as Button; Button bb = sender as Button;
if (bb.Tag.GetType() == typeof(Button)) { if (bb.Tag.GetType() == typeof(Button)) {
@ -180,7 +180,9 @@ namespace BetterJoyForCemu {
if (button.Tag.GetType() == typeof(Joycon)) { if (button.Tag.GetType() == typeof(Joycon)) {
Joycon v = (Joycon)button.Tag; Joycon v = (Joycon)button.Tag;
v.SetRumble(160.0f, 320.0f, 1.0f, 300); v.SetRumble(160.0f, 320.0f, 1.0f);
await Task.Delay(300);
v.SetRumble(160.0f, 320.0f, 0);
} }
} }
} }

View file

@ -229,7 +229,7 @@ namespace BetterJoyForCemu {
form.loc[ii].Invoke(new MethodInvoker(delegate { form.loc[ii].Invoke(new MethodInvoker(delegate {
form.loc[ii].Tag = v; form.loc[ii].Tag = v;
form.loc[ii].Click += new EventHandler(form.locBtnClick); form.loc[ii].Click += new EventHandler(form.locBtnClickAsync);
})); }));
break; break;