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 -->
<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.-->
<!--Don't set above ~1200. Default: 40 and 120 -->
<!--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 struct Rumble {
private float h_f, l_f;
public float amp;
public bool controller_informed;
public long end_rumble_time_milliseconds;
public Queue<float[]> queue;
public void set_vals(float low_freq, float high_freq, float amplitude, int rumble_duration_ms = 0) {
h_f = high_freq;
amp = amplitude;
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 void set_vals(float low_freq, float high_freq, float amplitude) {
float[] rumbleQueue = new float[] {low_freq, high_freq, amplitude};
queue.Enqueue(rumbleQueue);
}
public Rumble(float low_freq, float high_freq, float amplitude, int rumble_duration_ms = 0) {
h_f = high_freq;
amp = amplitude;
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[] rumble_info) {
queue = new Queue<float[]>();
queue.Enqueue(rumble_info);
}
private float clamp(float x, float min, float max) {
if (x < min) return min;
if (x > max) return max;
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) {
byte en_amp;
@ -181,21 +156,22 @@ namespace BetterJoyForCemu {
public byte[] GetData() {
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[1] = 0x1;
rumble_data[2] = 0x40;
rumble_data[3] = 0x40;
} else {
l_f = clamp(l_f, 40.875885f, 626.286133f);
h_f = clamp(h_f, 81.75177f, 1252.572266f);
queued_data[0] = clamp(queued_data[0], 40.875885f, 626.286133f);
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);
byte lf = (byte)(Math.Round(32f * Math.Log(l_f * 0.1f, 2)) - 0x40);
byte hf_amp = EncodeAmp(amp);
UInt16 hf = (UInt16)((Math.Round(32f * Math.Log(queued_data[1] * 0.1f, 2)) - 0x60) * 4);
byte lf = (byte)(Math.Round(32f * Math.Log(queued_data[0] * 0.1f, 2)) - 0x40);
byte hf_amp = EncodeAmp(queued_data[2]);
UInt16 lf_amp = (UInt16)(Math.Round((double)hf_amp) * .5);
byte parity = (byte)(lf_amp % 2);
@ -243,7 +219,6 @@ namespace BetterJoyForCemu {
ushort ds4_ts = 0;
ulong lag;
int rumblePeriod = Int32.Parse(ConfigurationManager.AppSettings["RumblePeriod"]);
int lowFreq = Int32.Parse(ConfigurationManager.AppSettings["LowFreqRumble"]);
int highFreq = Int32.Parse(ConfigurationManager.AppSettings["HighFreqRumble"]);
@ -267,7 +242,7 @@ namespace BetterJoyForCemu {
handle = handle_;
imu_enabled = imu;
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++)
buttons_down_timestamp[i] = -1;
filterweight = alpha;
@ -302,17 +277,19 @@ namespace BetterJoyForCemu {
}
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)
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) {
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)
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) {
@ -787,10 +764,12 @@ namespace BetterJoyForCemu {
stop_polling = false;
int attempts = 0;
while (!stop_polling & state > state_.NO_JOYCONS) {
rumble_obj.Update();
if (!rumble_obj.controller_informed) {
if (rumble_obj.queue.Count > 0) {
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();
@ -1057,9 +1036,9 @@ namespace BetterJoyForCemu {
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;
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) {

View file

@ -172,7 +172,7 @@ namespace BetterJoyForCemu {
bool showAsXInput = Boolean.Parse(ConfigurationManager.AppSettings["ShowAsXInput"]);
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;
if (bb.Tag.GetType() == typeof(Button)) {
@ -180,7 +180,9 @@ namespace BetterJoyForCemu {
if (button.Tag.GetType() == typeof(Joycon)) {
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].Tag = v;
form.loc[ii].Click += new EventHandler(form.locBtnClick);
form.loc[ii].Click += new EventHandler(form.locBtnClickAsync);
}));
break;