From 0003a37f350837ce216df2ddf3bccf1f71631592 Mon Sep 17 00:00:00 2001 From: Miguel Guthridge Date: Mon, 2 May 2022 02:44:27 +1000 Subject: [PATCH] Add disgusting workaround for an FL bug When switching to an effect plugin, there's now a 3 tick delay before it is activated, since sometimes closing a generator plugin causes FL to think that an effect plugin is open which causes a crash if the script tries to do anything with that plugin --- src/common/activitystate.py | 7 +++- src/common/defaultconfig.py | 6 ++-- src/common/util/apifixes.py | 65 ++++++++++++++++++++++++++----------- 3 files changed, 55 insertions(+), 23 deletions(-) diff --git a/src/common/activitystate.py b/src/common/activitystate.py index 9b90ae0c..f8194cfa 100644 --- a/src/common/activitystate.py +++ b/src/common/activitystate.py @@ -8,6 +8,7 @@ * Miguel Guthridge [hdsq@outlook.com, HDSQ#2154] """ +from common.profiler import profilerDecoration from common.logger import log, verbosity from common.util.apifixes import ( PluginIndex, @@ -16,7 +17,8 @@ EffectIndex, WindowIndex, ) -from common.util.apifixes import getFocusedPluginIndex, getFocusedWindowIndex +from common.util.apifixes import getFocusedPluginIndex, getFocusedWindowIndex,\ + reset_generator_active class ActivityState: @@ -71,10 +73,13 @@ def _forcePlugUpdate(self) -> None: else: self._effect = plugin # type: ignore + @profilerDecoration("activity.tick") def tick(self) -> None: """ Called frequently when we need to update the current window """ + # HACK: Fix FL Studio bugs + reset_generator_active() self._changed = False if self._doUpdate: # Manually update plugin using selection diff --git a/src/common/defaultconfig.py b/src/common/defaultconfig.py index 28ccddc5..bafb20e6 100644 --- a/src/common/defaultconfig.py +++ b/src/common/defaultconfig.py @@ -32,11 +32,11 @@ # Settings used for debugging "debug": { # Whether performance profiling should be enabled - "profiling": True, + "profiling": False, # Whether profiling should print the tracing of profiler contexts # within the script. Useful for troubleshooting crashes in FL Studio's - # MIDI API. Requires profiling to be enabled - "exec_tracing": True + # MIDI API. Requires profiling to be enabled. + "exec_tracing": False }, # Settings used during script initialisation "bootstrap": { diff --git a/src/common/util/apifixes.py b/src/common/util/apifixes.py index 8b4e5b19..7b2630ed 100644 --- a/src/common/util/apifixes.py +++ b/src/common/util/apifixes.py @@ -12,6 +12,7 @@ import playlist from typing import Union, Optional +from common.profiler import profilerDecoration, ProfilerContext from common.consts import PARAM_CC_START GeneratorIndex = tuple[int] @@ -29,11 +30,25 @@ UnsafeIndex = Union[UnsafePluginIndex, UnsafeWindowIndex] +# HACK: A terrible horrible no good really bad global variable to make sure +# that we hopefully avoid crashes in getFocusedPluginIndex +generator_previously_active = 0 + + +def reset_generator_active(): + """Horrible hacky function to hopefully work around a bug in FL Studio""" + global generator_previously_active + if generator_previously_active != 0: + generator_previously_active -= 1 + + +@profilerDecoration("getFocusedPluginIndex") def getFocusedPluginIndex(force: bool = False) -> UnsafePluginIndex: """ Fixes the horrible ui.getFocusedFormIndex() function - Values are returned as tuples so that they can be unwrapped when + Values are returned as tuples so that they can be unwrapped when being + passed to other API functions Args: * `force` (`bool`, optional): whether to return the selected plugin on the @@ -44,18 +59,31 @@ def getFocusedPluginIndex(force: bool = False) -> UnsafePluginIndex: * `int`: grouped index of a channel rack plugin if one is focused * `int, int`: index of a mixer plugin if one is focused """ - # Check if a channel rack plugin is focused - # if ui.getFocused(7): - form_id = ui.getFocusedFormID() - + # HACK: Move this elsewhere + global generator_previously_active + with ProfilerContext("getFocused"): + # for i in range(8): + # print(f" {ui.getFocused(i)=}, {i=}") + ui_6 = ui.getFocused(6) + ui_7 = ui.getFocused(7) # If a mixer plugin is focused - if ui.getFocused(6): + if ui_6: + # HACK: Error checking to hopefully avoid a crash due to bugs in FL + # Studio + if generator_previously_active: + print("getFocusedPluginIndex() crash prevention") + return None + with ProfilerContext("getFocusedFormID @ mixer"): + form_id = ui.getFocusedFormID() track = form_id // 4194304 slot = (form_id - 4194304 * track) // 65536 return track, slot # Otherwise, assume that a channel is selected # Use the channel rack index so that we always have one - elif ui.getFocused(7): + elif ui_7: + generator_previously_active = 3 + with ProfilerContext("getFocusedFormID @ cr"): + form_id = ui.getFocusedFormID() # NOTE: When using groups, ui.getFocusedFormID() returns the index # respecting groups, instead of the global index, yuck if form_id == -1: @@ -63,30 +91,29 @@ def getFocusedPluginIndex(force: bool = False) -> UnsafePluginIndex: return None return (form_id,) else: + generator_previously_active = 3 if force: - return (channels.selectedChannel(),) + with ProfilerContext("selectedChannel"): + ret = (channels.selectedChannel(),) + return ret else: return None +@profilerDecoration("getFocusedWindowIndex") def getFocusedWindowIndex() -> Optional[int]: """ - Fixes the horrible ui.getFocusedFormIndex() function - - Values are returned as tuples so that they can be unwrapped when + Fixes the horrible ui.getFocused() function Returns: * `None`: if no window is focused * `int`: index of window """ - # Check if a channel rack plugin is focused - if getFocusedPluginIndex() is not None: - return None - else: - ret = ui.getFocusedFormID() - if ret == -1: - return None - return ret + for i in range(5): + if ui.getFocused(i): + return i + return None + # def getPluginName(index: UnsafeIndex) -> str: # """