mirror of
https://github.com/EyeTrackVR/EyeTrackVR.git
synced 2025-09-26 23:09:28 +08:00

* initial changes * Mostly clean up, refactor registering listeners to make sense, backport tests * Add initial implementation of VRCFTModuleSender * Add basic GUI for the modules settings * Fix tooltip descriptions # TODO: # - there's ghosts in the machine - vrc osc is not working properly # - min/maxing will require field combinators in the modules lmao * Fix type validation bugs, fix typos # TODO: # - there's ghosts in the machine - vrc osc is not working properly # - min/maxing will require field combinators in the modules lmao * Add checkbox to switch to ETVR Module # TODO: # - there's ghosts in the machine - vrc osc is not working properly # - min/maxing will require field combinators in the modules lmao * Black stuff # TODO: # - there's ghosts in the machine - vrc osc is not working properly # - min/maxing will require field combinators in the modules lmao * Remove coverage by default # TODO: # - there's ghosts in the machine - vrc osc is not working properly # - min/maxing will require field combinators in the modules lmao * Fix timeout in tests # TODO: # - there's ghosts in the machine - vrc osc is not working properly # - min/maxing will require field combinators in the modules lmao * HEAVY WIP: Refactor native output, NOTE: I brought back the entire old OSC implementation as a live reference, this will be removed once I'm done. This also lays ground for other modes as they're pretty similar # TODO: # - there's ghosts in the machine - vrc osc is not working properly # - min/maxing will require field combinators in the modules lmao * HEAVY WIP: Refactor v1 params output, # TODO: # - min/maxing will require field combinators in the modules lmao * HEAVY WIP: Refactor v2 params output # TODO: # - min/maxing will require field combinators in the modules lmao * Finish refactoring v2 and v1, fixup tests, refactor native # TODO: # - min/maxing will require field combinators in the modules lmao * Add tests for v1 params # TODO: # - min/maxing will require field combinators in the modules lmao * Add tests for native params # TODO: # - min/maxing will require field combinators in the modules lmao * Fix OSC not getting up after config reset. Remove reset command, config sends everything changed anyway, sunset the idea of using single client and thus simplify the code a bit # TODO: # - min/maxing will require field combinators in the modules lmao * Rename gui_PortNumber to gui_VRCFTModulePort for readability # TODO: # - min/maxing will require field combinators in the modules lmao * Cleanup EyeID usage # TODO: # - min/maxing will require field combinators in the modules lmao * Cleanup osc after rebase # TODO: # - min/maxing will require field combinators in the modules lmao * Make VRChatOSCSender a bit more readable # TODO: # - min/maxing will require field combinators in the modules lmao * Remove unsued VRChatOSCReceiver, this is taken care of by generic OSCReceiver # TODO: # - min/maxing will require field combinators in the modules lmao * Commit crimes with try_convert_to_float to make osc, pysimplegui and pydantic happy * Cleanup after merge * Disable emulation by default * Fix OSCReceiver crashing on unknown addresses * Adjust VRCFT Module settings to look better in game * Fix recalibrate and recenter for OSC only working for the right eye * Fix save and restart button not restarting the tracking * Fix broken tracking on v1 params for eye_x, clean up implementation * Fix regular value being passed to OSC listeners instead of OSCMessage * Add a TODO, probably to be ignored * Add support for custom ETVR VRCFT Module listening address
83 lines
2.5 KiB
Python
83 lines
2.5 KiB
Python
import os
|
|
import typing
|
|
import sys
|
|
|
|
from pathlib import Path
|
|
from typing import Union
|
|
|
|
is_nt = True if os.name == "nt" else False
|
|
|
|
|
|
def PlaySound(*args, **kwargs):
|
|
pass
|
|
|
|
|
|
SND_FILENAME = SND_ASYNC = 1
|
|
|
|
if is_nt:
|
|
import winsound
|
|
|
|
PlaySound = winsound.PlaySound
|
|
SND_FILENAME = winsound.SND_FILENAME
|
|
SND_ASYNC = winsound.SND_ASYNC
|
|
|
|
|
|
def clamp(x, low, high):
|
|
return max(low, min(x, high))
|
|
|
|
|
|
def lst_median(lst, ordered=False):
|
|
# https://github.com/emilianavt/OpenSeeFace/blob/6f24efc4f58eb7cca47ec2146d934eabcc207e46/remedian.py
|
|
assert lst, "median needs a non-empty list"
|
|
n = len(lst)
|
|
p = q = n // 2
|
|
if n < 3:
|
|
p, q = 0, n - 1
|
|
else:
|
|
lst = lst if ordered else sorted(lst)
|
|
if not n % 2: # for even-length lists, use mean of mid 2 nums
|
|
q = p - 1
|
|
return lst[p] if p == q else (lst[p] + lst[q]) / 2
|
|
|
|
|
|
class FastMedian:
|
|
# https://github.com/emilianavt/OpenSeeFace/blob/6f24efc4f58eb7cca47ec2146d934eabcc207e46/remedian.py
|
|
# Initialization
|
|
def __init__(self, inits: typing.Optional[typing.Sequence] = [], k=64): # after some experimentation, 64 works ok
|
|
self.all, self.k = [], k
|
|
self.more, self.__median = None, None
|
|
if inits is not None:
|
|
[self + x for x in inits]
|
|
|
|
# When full, push the median of current values to next list, then reset.
|
|
def __add__(self, x):
|
|
self.__median = None
|
|
self.all.append(x) # It would be faster to pre-allocate an array and assign it by index.
|
|
if len(self.all) == self.k:
|
|
self.more = self.more or FastMedian(k=self.k)
|
|
self.more + self.__medianPrim(self.all)
|
|
# It's going to be slower because of the re-allocation.
|
|
self.all = [] # reset
|
|
|
|
# If there is a next list, ask its median. Else, work it out locally.
|
|
def median(self):
|
|
return self.more.median() if self.more else self.__medianPrim(self.all)
|
|
|
|
# Only recompute median if we do not know it already.
|
|
def __medianPrim(self, all):
|
|
if self.__median is None:
|
|
self.__median = lst_median(all, ordered=False)
|
|
return self.__median
|
|
|
|
def resource_path(relative_path: Union[str, Path]) -> str:
|
|
"""
|
|
Get absolute path to resource, works for dev and for PyInstaller
|
|
"""
|
|
try:
|
|
# PyInstaller creates a temp folder and stores path in _MEIPASS
|
|
base_path = Path(sys._MEIPASS)
|
|
except AttributeError:
|
|
base_path = Path(".")
|
|
|
|
return str(base_path / relative_path)
|