From 7857d759eedb667f1ab383814dfd0640305ead30 Mon Sep 17 00:00:00 2001 From: Maddy Guthridge Date: Thu, 14 Aug 2025 19:26:19 +1000 Subject: [PATCH 1/2] Handle and log RuntimeError in manual mapper tick event callback This issue was reported by two users, who indicated that it caused enormous amounts of logs to be produced, eventually crashing FL Studio. Currently, I don't have the energy to fully investigate, so this commit just silences the exception after logging it --- src/common/consts.py | 4 +- src/plugs/special/manual_mapper.py | 91 ++++++++++++++++++------------ 2 files changed, 58 insertions(+), 37 deletions(-) diff --git a/src/common/consts.py b/src/common/consts.py index f1de21ad..b8be008e 100644 --- a/src/common/consts.py +++ b/src/common/consts.py @@ -11,13 +11,13 @@ """ # Version info -VERSION = (1, 2, 2) +VERSION = (1, 2, 3) # Sub versions VERSION_MAJOR = VERSION[0] VERSION_MINOR = VERSION[1] VERSION_REVISION = VERSION[2] -VERSION_SUFFIX = "" +VERSION_SUFFIX = "beta-1" # Minimum API version required to run script MIN_API_VERSION = 19 diff --git a/src/plugs/special/manual_mapper.py b/src/plugs/special/manual_mapper.py index 2d857803..3eaf2ab2 100644 --- a/src/plugs/special/manual_mapper.py +++ b/src/plugs/special/manual_mapper.py @@ -13,10 +13,13 @@ This code is licensed under the GPL v3 license. Refer to the LICENSE file for more details. """ + from typing import Optional import device import general import midi +from common.logger import verbosity +from common.logger.logger import log from common.types import Color from common.extension_manager import ExtensionManager from control_surfaces import ( @@ -32,10 +35,7 @@ # Only assign to CC values that are undefined by the MIDI spec AVAILABLE_CCS = ( - [3, 9, 14, 15] - + list(range(20, 32)) - + list(range(85, 91)) - + list(range(102, 120)) + [3, 9, 14, 15] + list(range(20, 32)) + list(range(85, 91)) + list(range(102, 120)) ) NUM_CCS = len(AVAILABLE_CCS) # = 40 @@ -52,32 +52,44 @@ class ManualMapper(SpecialPlugin): def __init__(self, shadow: DeviceShadow) -> None: shadow.setMinimal(True) self._faders_start = 0 - self._knobs_start = len(shadow.bindMatches( - # https://github.com/python/mypy/issues/4717 is the bane of my - # existence - GenericFader, # type: ignore - self.eFaders, - self.tFaders, - allow_substitution=False, - one_type=False, - args_generator=..., - )) - self._encoders_start = len(shadow.bindMatches( - Encoder, - self.eEncoders, - self.tEncoders, - allow_substitution=False, - one_type=False, - args_generator=..., - )) + self._knobs_start - self._mods_start = len(shadow.bindMatches( - GenericKnob, # type: ignore - self.eKnobs, - self.tKnobs, - allow_substitution=False, - one_type=False, - args_generator=..., - )) + self._encoders_start + self._knobs_start = len( + shadow.bindMatches( + # https://github.com/python/mypy/issues/4717 is the bane of my + # existence + GenericFader, # type: ignore + self.eFaders, + self.tFaders, + allow_substitution=False, + one_type=False, + args_generator=..., + ) + ) + self._encoders_start = ( + len( + shadow.bindMatches( + Encoder, + self.eEncoders, + self.tEncoders, + allow_substitution=False, + one_type=False, + args_generator=..., + ) + ) + + self._knobs_start + ) + self._mods_start = ( + len( + shadow.bindMatches( + GenericKnob, # type: ignore + self.eKnobs, + self.tKnobs, + allow_substitution=False, + one_type=False, + args_generator=..., + ) + ) + + self._encoders_start + ) shadow.bindMatches( ModXY, self.eMods, @@ -88,7 +100,7 @@ def __init__(self, shadow: DeviceShadow) -> None: super().__init__(shadow, []) @classmethod - def create(cls, shadow: DeviceShadow) -> 'SpecialPlugin': + def create(cls, shadow: DeviceShadow) -> "SpecialPlugin": return cls(shadow) @classmethod @@ -167,10 +179,19 @@ def tickEvent(cls, control: ControlShadow, c_index: int): event_id = cls.calcEventId(channel, cc) # If that event ID isn't invalid if event_id is not None: - control.connected = True - control.annotation = device.getLinkedParamName(event_id) - control.color = Color.ENABLED - control.value = device.getLinkedValue(event_id) + try: + control.connected = True + control.annotation = device.getLinkedParamName(event_id) + control.color = Color.ENABLED + control.value = device.getLinkedValue(event_id) + except RuntimeError as e: + log( + "plugs.special.manual_mapper", + "error when ticking linked param", + verbosity.ERROR, + f"Event ID was {event_id}, exception was {e}", + ) + control.connected = False else: control.connected = False From d28646e3437193bab0c5a12a9671d173b65383af Mon Sep 17 00:00:00 2001 From: Maddy Guthridge Date: Thu, 14 Aug 2025 19:34:05 +1000 Subject: [PATCH 2/2] Fix linter --- src/plugs/special/manual_mapper.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugs/special/manual_mapper.py b/src/plugs/special/manual_mapper.py index 3eaf2ab2..45b95dc8 100644 --- a/src/plugs/special/manual_mapper.py +++ b/src/plugs/special/manual_mapper.py @@ -35,7 +35,10 @@ # Only assign to CC values that are undefined by the MIDI spec AVAILABLE_CCS = ( - [3, 9, 14, 15] + list(range(20, 32)) + list(range(85, 91)) + list(range(102, 120)) + [3, 9, 14, 15] + + list(range(20, 32)) + + list(range(85, 91)) + + list(range(102, 120)) ) NUM_CCS = len(AVAILABLE_CCS) # = 40