From c17fc6ef54440b4a4fe84f4965ad8edbdb65b50f Mon Sep 17 00:00:00 2001 From: Alexandre Almeida <1251067+Xinayder@users.noreply.github.com> Date: Fri, 8 Aug 2025 16:34:39 +0200 Subject: [PATCH] Add M-VAVE SMK25-II controller --- src/devices/mvave/__init__.py | 12 +++ src/devices/mvave/smk25_ii/__init__.py | 16 ++++ src/devices/mvave/smk25_ii/smk25_ii.py | 101 +++++++++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 src/devices/mvave/__init__.py create mode 100644 src/devices/mvave/smk25_ii/__init__.py create mode 100644 src/devices/mvave/smk25_ii/smk25_ii.py diff --git a/src/devices/mvave/__init__.py b/src/devices/mvave/__init__.py new file mode 100644 index 00000000..9b2b11cb --- /dev/null +++ b/src/devices/mvave/__init__.py @@ -0,0 +1,12 @@ +""" +devices > mvave + +Authors: +* Xinayder + +This code is licensed under the GPL v3 license. Refer to the LICENSE file for +more details. +""" +__all__ = ['smk25_ii'] + +from . import smk25_ii diff --git a/src/devices/mvave/smk25_ii/__init__.py b/src/devices/mvave/smk25_ii/__init__.py new file mode 100644 index 00000000..ab306e35 --- /dev/null +++ b/src/devices/mvave/smk25_ii/__init__.py @@ -0,0 +1,16 @@ +""" +devices > mvave > smk25_ii + +M-VAVE SMK25-II + +Authors: +* Xinayder + +This code is licensed under the GPL v3 license. Refer to the LICENSE file for +more details. +""" +__all__ = [ + 'smk25_ii' +] + +from . import smk25_ii diff --git a/src/devices/mvave/smk25_ii/smk25_ii.py b/src/devices/mvave/smk25_ii/smk25_ii.py new file mode 100644 index 00000000..744db630 --- /dev/null +++ b/src/devices/mvave/smk25_ii/smk25_ii.py @@ -0,0 +1,101 @@ +""" +devices > mvave > smk25_ii > smk25_ii + +Definition for the M-VAVE SMK25-II controller. + +There are labels for transport controls, but I haven't gotten to adding them. +They share the same keys as the drum pad. + +Authors: +* Xinayder + +This code is licensed under the GPL v3 license. Refer to the LICENSE file for +more details. +""" + +from typing import Optional + +from fl_classes import FlMidiMsg + +from common.extension_manager import ExtensionManager +from control_surfaces import ( + ChannelAfterTouch, + ControlSwitchButton, + Fader, + FastForwardButton, + Knob, + MuteButton, + PlayButton, + RecordButton, + RewindButton, + SoloButton, + StopButton, + DirectionLeft, + DirectionRight, + UndoButton, + DrumPad, + StandardModWheel, + StandardPitchWheel, +) +from control_surfaces.event_patterns import BasicPattern, IEventPattern, NotePattern +from control_surfaces.matchers import BasicControlMatcher, NoteMatcher +from control_surfaces.value_strategies import ( + ButtonData2Strategy, + Data2Strategy, + NoteStrategy, +) +from devices.device import Device + +class SMK25II(Device): + """M-VAVE SMK25-II + """ + + def __init__(self) -> None: + matcher = BasicControlMatcher() + + matcher.addSubMatcher(NoteMatcher()) + matcher.addControl(StandardPitchWheel.create()) + matcher.addControl(StandardModWheel.create()) + matcher.addControl(ChannelAfterTouch.fromChannel(...)) + + matcher.addControls([ + DrumPad(NotePattern(i, 9), NoteStrategy(), (i // 8, i % 8)) + for i in range(16) + ], 10) + + + for i in range(8): + # Knobs + matcher.addControl(Knob( + BasicPattern(0xB0, 0x1E + i, ...), + Data2Strategy(), + (0, i) + )) + + super().__init__(matcher) + + @classmethod + def getDrumPadSize(cls) -> tuple[int, int]: + return 2, 8 + + @classmethod + def matchDeviceName(cls, name: str) -> bool: + return name.startswith("SINCO - SINCO SMK25II") + + @classmethod + def create( + cls, + event: Optional[FlMidiMsg] = None, + id: Optional[str] = None, + ) -> 'Device': + return cls() + + def getId(self) -> str: + return "MVAVE.SMK25.II" + + @classmethod + def getSupportedIds(cls) -> tuple[str, ...]: + return ("MVAVE.SMK25.II",) + + +ExtensionManager.devices.register(SMK25II)