Skip to content

Commit 8b46c69

Browse files
committedMay 17, 2022
Create value strategy for twos compliement delta encoders
1 parent 18e51f9 commit 8b46c69

File tree

6 files changed

+110
-2
lines changed

6 files changed

+110
-2
lines changed
 

‎coverage.sh

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
coverage run -m pytest && coverage report && coverage html && python -m webbrowser htmlcov/index.html > /dev/null 2>&1

‎src/common/states/devicedetect.py

-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@ def processEvent(self, event: EventData) -> None:
164164
verbosity.INFO,
165165
eventToString(event)
166166
)
167-
event.handled = True
168167
common.getContext().setState(self._to.create(dev))
169168
except DeviceRecogniseError:
170169
log(

‎src/common/util/misc.py

+15
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,18 @@ def formatLongTime(t: float) -> str:
7878
t_obj = time.localtime(t)
7979
ms = f"{t - math.floor(t):.3}".lstrip("0.")
8080
return f"{t_obj.tm_hour:02}:{t_obj.tm_min:02}:{t_obj.tm_sec:02}.{ms}"
81+
82+
83+
def clamp(value: float, lower: float, upper: float) -> float:
84+
"""
85+
Clamp value between lower and upper
86+
87+
### Args:
88+
* `value` (`float`): value to clamp
89+
* `lower` (`float`): lowest allowed value
90+
* `upper` (`float`): greatest allowed value
91+
92+
### Returns:
93+
* `float`: clamped value
94+
"""
95+
return min(max(value, lower), upper)

‎src/controlsurfaces/valuestrategies/__init__.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,18 @@
1313
'NoteStrategy',
1414
'Data2Strategy',
1515
'Data1Strategy',
16+
'TwosComplimentDeltaStrategy',
1617
'ButtonData2Strategy',
1718
'ButtonSinglePressStrategy',
1819
'ForwardedStrategy',
1920
'ForwardedUnionStrategy',
20-
'NullEventStrategy'
21+
'NullEventStrategy',
2122
]
2223

2324
from .ivaluestrategy import IValueStrategy
2425
from .notestrategy import NoteStrategy
2526
from .datastrategy import Data2Strategy, Data1Strategy
27+
from .twoscomplimentdelta import TwosComplimentDeltaStrategy
2628
from .buttondata2strategy import ButtonData2Strategy
2729
from .buttonsinglepressstrategy import ButtonSinglePressStrategy
2830
from .forwardedstrategy import ForwardedStrategy, ForwardedUnionStrategy
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""
2+
controlsurfaces > valuestrategies > twoscomplimentdelta
3+
4+
Contains the definitions for a two's compliment delta value strategy
5+
6+
Authors:
7+
* Miguel Guthridge [hdsq@outlook.com.au, HDSQ#2154]
8+
"""
9+
from common.types.eventdata import EventData, isEventStandard
10+
from common.util.misc import clamp
11+
from . import IValueStrategy
12+
13+
14+
class TwosComplimentDeltaStrategy(IValueStrategy):
15+
"""
16+
Defines a value strategy that gets its values relative to the current
17+
value, using the data2 property of events to calculate an offset using
18+
two's compliment. This is used by many endless encoders.
19+
"""
20+
def __init__(self, scaling: float = 1.0) -> None:
21+
"""
22+
Create a TwosComplimentDeltaStrategy
23+
24+
### Args:
25+
* `scaling` (`float`, optional): amount to scale deltas by. Defaults to
26+
`1.0`.
27+
"""
28+
self.__scaling = scaling
29+
30+
def getValueFromEvent(self, event: EventData, value: float) -> float:
31+
assert isEventStandard(event)
32+
if event.data2 < 64:
33+
# Positive
34+
delta = event.data2
35+
else:
36+
delta = event.data2 - 128
37+
return clamp((delta / 64) * self.__scaling + value, 0.0, 1.0)
38+
39+
def getChannelFromEvent(self, event: EventData) -> int:
40+
assert isEventStandard(event)
41+
return event.status & 0xF
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
2+
import pytest
3+
from common.types import EventData
4+
from controlsurfaces.valuestrategies import TwosComplimentDeltaStrategy
5+
6+
7+
def test_zero():
8+
s = TwosComplimentDeltaStrategy()
9+
e = EventData(0, 0, 0)
10+
assert s.getValueFromEvent(e, 0.5) == 0.5
11+
12+
13+
def test_positive():
14+
s = TwosComplimentDeltaStrategy()
15+
e = EventData(0, 0, 1)
16+
assert s.getValueFromEvent(e, 0.5) == 0.5 + 1/64
17+
e = EventData(0, 0, 5)
18+
assert s.getValueFromEvent(e, 0.5) == 0.5 + 5/64
19+
20+
21+
def test_negative():
22+
s = TwosComplimentDeltaStrategy()
23+
e = EventData(0, 0, 127)
24+
assert s.getValueFromEvent(e, 0.5) == 0.5 - 1/64
25+
e = EventData(0, 0, 123)
26+
assert s.getValueFromEvent(e, 0.5) == 0.5 - 5/64
27+
28+
29+
@pytest.mark.parametrize(
30+
'e', [
31+
EventData(0, 0, 1),
32+
EventData(0, 0, 127),
33+
EventData(0, 0, 0),
34+
EventData(0, 0, 5),
35+
]
36+
)
37+
def test_scaling(e):
38+
s1 = TwosComplimentDeltaStrategy()
39+
s2 = TwosComplimentDeltaStrategy(2.0)
40+
delta = s1.getValueFromEvent(e, 0.5) - 0.5
41+
assert s2.getValueFromEvent(e, 0.5) - 0.5 == delta * 2
42+
43+
44+
def test_clamp():
45+
s = TwosComplimentDeltaStrategy()
46+
e = EventData(0, 0, 127)
47+
assert s.getValueFromEvent(e, 0.0) == 0.0
48+
e = EventData(0, 0, 1)
49+
assert s.getValueFromEvent(e, 1.0) == 1.0

0 commit comments

Comments
 (0)