From 6cb6418f07a0da9407fad061aa679a4933cef5bf Mon Sep 17 00:00:00 2001 From: Miguel Guthridge Date: Sun, 6 Feb 2022 16:23:50 +1100 Subject: [PATCH] Create UnionPattern event pattern --- common/__init__.py | 2 +- common/eventpattern/__init__.py | 5 ++-- common/eventpattern/basicpattern.py | 10 +++---- common/eventpattern/forwardedpattern.py | 2 +- common/eventpattern/unionpattern.py | 33 +++++++++++++++++++++ controlsurfaces/aftertouch.py | 6 ++-- controlsurfaces/note.py | 4 +-- controlsurfaces/pedal.py | 8 ++--- controlsurfaces/wheels.py | 8 ++--- devices/maudio/hammer88pro/hammer88pro.py | 22 +++++++------- devices/maudio/hammer88pro/hammerpitch.py | 4 +-- devices/novation/launchkey/mk2/launchkey.py | 28 ++++++++--------- tests/test_eventpattern.py | 14 ++++----- 13 files changed, 90 insertions(+), 56 deletions(-) create mode 100644 common/eventpattern/unionpattern.py diff --git a/common/__init__.py b/common/__init__.py index 1933f15f..e6d35723 100644 --- a/common/__init__.py +++ b/common/__init__.py @@ -11,7 +11,7 @@ from .logger import log, verbosity -from .eventpattern import BasicEventPattern, IEventPattern +from .eventpattern import BasicPattern, IEventPattern from .contextmanager import getContext, resetContext, catchContextResetException diff --git a/common/eventpattern/__init__.py b/common/eventpattern/__init__.py index 626065db..ea3015ed 100644 --- a/common/eventpattern/__init__.py +++ b/common/eventpattern/__init__.py @@ -1,5 +1,6 @@ from .bytematch import ByteMatch, fromNibbles from .ieventpattern import IEventPattern -from .basicpattern import BasicEventPattern -from .forwardedpattern import ForwardedEventPattern +from .basicpattern import BasicPattern +from .forwardedpattern import ForwardedPattern +from .unionpattern import UnionPattern diff --git a/common/eventpattern/basicpattern.py b/common/eventpattern/basicpattern.py index b91e6404..4d7b1ea7 100644 --- a/common/eventpattern/basicpattern.py +++ b/common/eventpattern/basicpattern.py @@ -4,7 +4,7 @@ from common.types import eventData from . import ByteMatch, IEventPattern -class BasicEventPattern(IEventPattern): +class BasicPattern(IEventPattern): """ Represents a pattern to match with MIDI events. @@ -129,10 +129,10 @@ def _matchByte(expected: ByteMatch, actual: int) -> bool: """ # This is type-safe, I promise matches: dict[type, Callable[[Any, int], bool]] = { - int: BasicEventPattern._matchByteConst, - range: BasicEventPattern._matchByteRange, - tuple: BasicEventPattern._matchByteTuple, - type(...): BasicEventPattern._matchByteEllipsis + int: BasicPattern._matchByteConst, + range: BasicPattern._matchByteRange, + tuple: BasicPattern._matchByteTuple, + type(...): BasicPattern._matchByteEllipsis } return matches[type(expected)](expected, actual) diff --git a/common/eventpattern/forwardedpattern.py b/common/eventpattern/forwardedpattern.py index ff82eedb..0a782e96 100644 --- a/common/eventpattern/forwardedpattern.py +++ b/common/eventpattern/forwardedpattern.py @@ -15,7 +15,7 @@ from common.types import eventData -class ForwardedEventPattern(IEventPattern): +class ForwardedPattern(IEventPattern): """ The forwarded pattern is used to parse data from events which were forwarded from the Universal Event Forwarded device script. diff --git a/common/eventpattern/unionpattern.py b/common/eventpattern/unionpattern.py new file mode 100644 index 00000000..6f75d206 --- /dev/null +++ b/common/eventpattern/unionpattern.py @@ -0,0 +1,33 @@ +""" +common > eventpattern > unionpattern + +Contains the definition for the union type event pattern, which allows events +to be detected if they match any of a number of patterns. + +Authors: +* Miguel Guthridge [hdsq@outlook.com.au, HDSQ#2154] +""" + +from common.types import eventData +from .ieventpattern import IEventPattern + +class UnionPattern(IEventPattern): + """ + Represents the union of multiple event patterns. A match with any of those + patterns is considered a match overall. + """ + + def __init__(self, *patterns: IEventPattern) -> None: + """ + Create a UnionPattern + + Args: + * `*patterns` (`IEventPattern`): event patterns to match, each as + separate arguments + """ + if len(patterns) < 2: + raise ValueError("Expected at least two event patterns to union") + self._patterns = patterns + + def matchEvent(self, event: 'eventData') -> bool: + return any(p.matchEvent(event) for p in self._patterns) diff --git a/controlsurfaces/aftertouch.py b/controlsurfaces/aftertouch.py index 68a702b2..b5bdb570 100644 --- a/controlsurfaces/aftertouch.py +++ b/controlsurfaces/aftertouch.py @@ -7,7 +7,7 @@ * Miguel Guthridge [hdsq@outlook.com.au, HDSQ#2154] """ -from common.eventpattern import BasicEventPattern, fromNibbles, IEventPattern +from common.eventpattern import BasicPattern, fromNibbles, IEventPattern from . import ControlSurface, IValueStrategy, Data2Strategy, Data1Strategy class AfterTouch(ControlSurface): @@ -39,7 +39,7 @@ class ChannelAfterTouch(AfterTouch): """ def __init__(self, channel: 'int|ellipsis' = ...) -> None: super().__init__( - BasicEventPattern(fromNibbles(0xD,channel), ..., ...), + BasicPattern(fromNibbles(0xD,channel), ..., ...), Data1Strategy() ) @@ -50,6 +50,6 @@ class NoteAfterTouch(AfterTouch): """ def __init__(self, note: int, channel: 'int|ellipsis' = ...) -> None: super().__init__( - BasicEventPattern(fromNibbles(0xA,channel), note, ...), + BasicPattern(fromNibbles(0xA,channel), note, ...), Data2Strategy() ) diff --git a/controlsurfaces/note.py b/controlsurfaces/note.py index 8eeb7d84..2a23ca51 100644 --- a/controlsurfaces/note.py +++ b/controlsurfaces/note.py @@ -7,7 +7,7 @@ * Miguel Guthridge [hdsq@outlook.com.au, HDSQ#2154] """ from common.types import eventData -from common.eventpattern import BasicEventPattern, fromNibbles +from common.eventpattern import BasicPattern, fromNibbles from . import ControlSurface, IValueStrategy class NoteValueStrategy(IValueStrategy): @@ -32,7 +32,7 @@ class Note(ControlSurface): """ def __init__(self, note_num: int, channel:int = 0) -> None: super().__init__( - BasicEventPattern(fromNibbles((8, 9), channel), note_num, ...), + BasicPattern(fromNibbles((8, 9), channel), note_num, ...), NoteValueStrategy(), "notes", (channel, note_num) diff --git a/controlsurfaces/pedal.py b/controlsurfaces/pedal.py index 819e7a4a..03795eb6 100644 --- a/controlsurfaces/pedal.py +++ b/controlsurfaces/pedal.py @@ -16,7 +16,7 @@ 'SOFT' ] -from common.eventpattern import BasicEventPattern, IEventPattern +from common.eventpattern import BasicPattern, IEventPattern from . import ControlSurface from .valuestrategies import ButtonData2Strategy @@ -47,18 +47,18 @@ class SustainPedal(Pedal): Represents a sustain pedal """ def __init__(self) -> None: - super().__init__(BasicEventPattern(0xB0, SUSTAIN, ...)) + super().__init__(BasicPattern(0xB0, SUSTAIN, ...)) class SostenutoPedal(Pedal): """ Represents a sostenuto pedal """ def __init__(self) -> None: - super().__init__(BasicEventPattern(0xB0, SOSTENUTO, ...)) + super().__init__(BasicPattern(0xB0, SOSTENUTO, ...)) class SoftPedal(Pedal): """ Represents a soft pedal """ def __init__(self) -> None: - super().__init__(BasicEventPattern(0xB0, SOFT, ...)) + super().__init__(BasicPattern(0xB0, SOFT, ...)) diff --git a/controlsurfaces/wheels.py b/controlsurfaces/wheels.py index f33c75a6..03993902 100644 --- a/controlsurfaces/wheels.py +++ b/controlsurfaces/wheels.py @@ -7,7 +7,7 @@ * Miguel Guthridge [hdsq@outlook.com.au, HDSQ#2154] """ -from common.eventpattern import IEventPattern, BasicEventPattern, fromNibbles +from common.eventpattern import IEventPattern, BasicPattern, fromNibbles from common.types import eventData from . import ControlSurface from . import Data2Strategy, IValueStrategy @@ -34,7 +34,7 @@ class StandardModWheel(ModWheel): """ def __init__(self) -> None: super().__init__( - BasicEventPattern(fromNibbles(0xB, ...), 0x1, ...), + BasicPattern(fromNibbles(0xB, ...), 0x1, ...), Data2Strategy(), "wheels" ) @@ -73,7 +73,7 @@ class StandardPitchWheel(PitchWheel): """ def __init__(self) -> None: super().__init__( - BasicEventPattern(fromNibbles(0xE, ...), ..., ...), + BasicPattern(fromNibbles(0xE, ...), ..., ...), PitchValueStrategy() ) @@ -84,6 +84,6 @@ class Data2PitchWheel(PitchWheel): """ def __init__(self) -> None: super().__init__( - BasicEventPattern(fromNibbles(0xE, ...), 0x0, ...), + BasicPattern(fromNibbles(0xE, ...), 0x0, ...), Data2Strategy() ) diff --git a/devices/maudio/hammer88pro/hammer88pro.py b/devices/maudio/hammer88pro/hammer88pro.py index 8f4c26a6..7c0ee735 100644 --- a/devices/maudio/hammer88pro/hammer88pro.py +++ b/devices/maudio/hammer88pro/hammer88pro.py @@ -1,7 +1,7 @@ from typing import Optional -from common.eventpattern import BasicEventPattern, ForwardedEventPattern +from common.eventpattern import BasicPattern, ForwardedPattern from common.types import eventData from common.extensionmanager import ExtensionManager from controlsurfaces.valuestrategies import ForwardedStrategy, ButtonData2Strategy @@ -34,10 +34,10 @@ def __init__(self) -> None: matcher = BasicControlMatcher() # Null events matcher.addControl(NullEvent( - BasicEventPattern(0xFA, 0x0, 0x0) + BasicPattern(0xFA, 0x0, 0x0) )) matcher.addControl(NullEvent( - BasicEventPattern(0xFC, 0x0, 0x0) + BasicPattern(0xFC, 0x0, 0x0) )) # Notes and pedals @@ -47,31 +47,31 @@ def __init__(self) -> None: # Transport buttons matcher.addControl(StopButton( - ForwardedEventPattern(3, BasicEventPattern(0xBF, 102, ...)), + ForwardedPattern(3, BasicPattern(0xBF, 102, ...)), ForwardedStrategy(ButtonData2Strategy()) )) matcher.addControl(PlayButton( - ForwardedEventPattern(3, BasicEventPattern(0xBF, 103, ...)), + ForwardedPattern(3, BasicPattern(0xBF, 103, ...)), ForwardedStrategy(ButtonData2Strategy()) )) matcher.addControl(RecordButton( - ForwardedEventPattern(3, BasicEventPattern(0xBF, 104, ...)), + ForwardedPattern(3, BasicPattern(0xBF, 104, ...)), ForwardedStrategy(ButtonData2Strategy()) )) matcher.addControl(RewindButton( - ForwardedEventPattern(3, BasicEventPattern(0xBF, 105, ...)), + ForwardedPattern(3, BasicPattern(0xBF, 105, ...)), ForwardedStrategy(ButtonData2Strategy()) )) matcher.addControl(FastForwardButton( - ForwardedEventPattern(3, BasicEventPattern(0xBF, 106, ...)), + ForwardedPattern(3, BasicPattern(0xBF, 106, ...)), ForwardedStrategy(ButtonData2Strategy()) )) matcher.addControl(LoopButton( - ForwardedEventPattern(3, BasicEventPattern(0xBF, 107, ...)), + ForwardedPattern(3, BasicPattern(0xBF, 107, ...)), ForwardedStrategy(ButtonData2Strategy()) )) matcher.addControl(MetronomeButton( - ForwardedEventPattern(3, BasicEventPattern(0xB9, 0x74, ...)), + ForwardedPattern(3, BasicPattern(0xB9, 0x74, ...)), ForwardedStrategy(ButtonData2Strategy()) )) matcher.addControl(StandardModWheel()) @@ -89,7 +89,7 @@ def getId() -> str: @staticmethod def getUniversalEnquiryResponsePattern(): - return BasicEventPattern( + return BasicPattern( [ 0xF0, # Sysex start 0x7E, # Device response diff --git a/devices/maudio/hammer88pro/hammerpitch.py b/devices/maudio/hammer88pro/hammerpitch.py index 67a87f85..258aba16 100644 --- a/devices/maudio/hammer88pro/hammerpitch.py +++ b/devices/maudio/hammer88pro/hammerpitch.py @@ -1,5 +1,5 @@ -from common.eventpattern import BasicEventPattern, fromNibbles +from common.eventpattern import BasicPattern, fromNibbles from controlsurfaces import PitchWheel from controlsurfaces.valuestrategies import Data2Strategy @@ -10,6 +10,6 @@ class HammerPitchWheel(PitchWheel): """ def __init__(self) -> None: super().__init__( - BasicEventPattern(fromNibbles(0xE, ...), (0x0, 0x7F), ...), + BasicPattern(fromNibbles(0xE, ...), (0x0, 0x7F), ...), Data2Strategy() ) diff --git a/devices/novation/launchkey/mk2/launchkey.py b/devices/novation/launchkey/mk2/launchkey.py index 2bf015bb..a4efb0d0 100644 --- a/devices/novation/launchkey/mk2/launchkey.py +++ b/devices/novation/launchkey/mk2/launchkey.py @@ -1,6 +1,6 @@ from typing import Optional -from common.eventpattern import BasicEventPattern +from common.eventpattern import BasicPattern from common.types import eventData from common.extensionmanager import ExtensionManager from controlsurfaces.valuestrategies import Data2Strategy @@ -40,7 +40,7 @@ def __init__(self, matcher: BasicControlMatcher) -> None: for i in range(1, 9): matcher.addControl( Knob( - BasicEventPattern(0xB0, 0x14 + i, ...), + BasicPattern(0xB0, 0x14 + i, ...), Data2Strategy(), "knobs", (i, 0) @@ -49,35 +49,35 @@ def __init__(self, matcher: BasicControlMatcher) -> None: # Transport matcher.addControl(StopButton( - BasicEventPattern(0xB0, 0x72, ...), + BasicPattern(0xB0, 0x72, ...), Data2Strategy() )) matcher.addControl(PlayButton( - BasicEventPattern(0xB0, 0x73, ...), + BasicPattern(0xB0, 0x73, ...), Data2Strategy() )) matcher.addControl(LoopButton( - BasicEventPattern(0xB0, 0x74, ...), + BasicPattern(0xB0, 0x74, ...), Data2Strategy(), )) matcher.addControl(RecordButton( - BasicEventPattern(0xB0, 0x75, ...), + BasicPattern(0xB0, 0x75, ...), Data2Strategy() )) matcher.addControl(DirectionNext( - BasicEventPattern(0xB0, 0x66, ...), + BasicPattern(0xB0, 0x66, ...), Data2Strategy() )) matcher.addControl(DirectionPrevious( - BasicEventPattern(0xB0, 0x67, ...), + BasicPattern(0xB0, 0x67, ...), Data2Strategy(), )) matcher.addControl(RewindButton( - BasicEventPattern(0xB0, 0x70, ...), + BasicPattern(0xB0, 0x70, ...), Data2Strategy(), )) matcher.addControl(FastForwardButton( - BasicEventPattern(0xB0, 0x71, ...), + BasicPattern(0xB0, 0x71, ...), Data2Strategy(), )) matcher.addControl(StandardPitchWheel()) @@ -98,7 +98,7 @@ def __init__(self) -> None: for i in range(1, 9): matcher.addControl( Fader( - BasicEventPattern(0xB0, 0x28 + i, ...), + BasicPattern(0xB0, 0x28 + i, ...), Data2Strategy(), "faders", (i, 0) @@ -107,7 +107,7 @@ def __init__(self) -> None: # Master fader matcher.addControl( Fader( - BasicEventPattern(0xB0, 0x07, ...), + BasicPattern(0xB0, 0x07, ...), Data2Strategy(), "knobs", (0, 0) @@ -126,7 +126,7 @@ def getId() -> str: @staticmethod def getUniversalEnquiryResponsePattern(): - return BasicEventPattern( + return BasicPattern( [ 0xF0, # Sysex start 0x7E, # Device response @@ -162,7 +162,7 @@ def getId() -> str: @staticmethod def getUniversalEnquiryResponsePattern(): - return BasicEventPattern( + return BasicPattern( [0xF0, 0x7E, 0x00, 0x06, 0x02, 0x00, 0x20, 0x29, 0x7B] ) diff --git a/tests/test_eventpattern.py b/tests/test_eventpattern.py index 924348d5..5350020e 100644 --- a/tests/test_eventpattern.py +++ b/tests/test_eventpattern.py @@ -4,34 +4,34 @@ Tests for event pattern matching """ -from common.eventpattern import BasicEventPattern +from common.eventpattern import BasicPattern from common.types import eventData def test_basic_pattern(): - p = BasicEventPattern(10, 10, 10) + p = BasicPattern(10, 10, 10) assert p.matchEvent(eventData(10, 10, 10)) assert not p.matchEvent(eventData(11, 10, 10)) def test_range_pattern(): - p = BasicEventPattern(range(10, 20), 4, 5) + p = BasicPattern(range(10, 20), 4, 5) assert p.matchEvent(eventData(13, 4, 5)) assert not p.matchEvent(eventData(20, 4, 5)) def test_tuple_pattern(): - p = BasicEventPattern((5, 12, 20), 4, 5) + p = BasicPattern((5, 12, 20), 4, 5) assert p.matchEvent(eventData(12, 4, 5)) assert not p.matchEvent(eventData(13, 4, 5)) def test_ellipsis_pattern(): - p = BasicEventPattern(..., 4, 5) + p = BasicPattern(..., 4, 5) assert p.matchEvent(eventData(12, 4, 5)) assert not p.matchEvent(eventData(128, 4, 5)) def test_sysex_pattern(): - p = BasicEventPattern([1, 3, 5, 7]) + p = BasicPattern([1, 3, 5, 7]) assert p.matchEvent(eventData([1, 3, 5, 7])) assert not p.matchEvent(eventData(1, 3, 5)) - p2 = BasicEventPattern(10, 10, 10) + p2 = BasicPattern(10, 10, 10) assert not p2.matchEvent(eventData([1, 3, 5, 7]))