diff --git a/ledfx/effects/gifbase.py b/ledfx/effects/gifbase.py new file mode 100644 index 000000000..d79900423 --- /dev/null +++ b/ledfx/effects/gifbase.py @@ -0,0 +1,48 @@ +import logging +from enum import Enum + +import voluptuous as vol +from PIL import Image + +from ledfx.effects import Effect + +_LOGGER = logging.getLogger(__name__) + + +class GIFResizeMethods(Enum): + # https://pillow.readthedocs.io/en/stable/handbook/concepts.html#filters-comparison-table + NEAREST = "Fastest" + BILINEAR = "Fast" + BICUBIC = "Slow" + LANCZOS = "Slowest" + + +@Effect.no_registration +class GifBase(Effect): + """ + Simple Gif base class that supplies basic gif and resize capability. + """ + + RESIZE_METHOD_MAPPING = { + GIFResizeMethods.NEAREST.value: Image.NEAREST, + GIFResizeMethods.BILINEAR.value: Image.BILINEAR, + GIFResizeMethods.BICUBIC.value: Image.BICUBIC, + GIFResizeMethods.LANCZOS.value: Image.LANCZOS, + } + + CONFIG_SCHEMA = vol.Schema( + { + vol.Optional( + "resize_method", + description="What strategy to use when resizing GIF", + default=GIFResizeMethods.BICUBIC.value, + ): vol.In( + [resize_method.value for resize_method in GIFResizeMethods] + ), + } + ) + + def config_updated(self, config): + self.resize_method = self.RESIZE_METHOD_MAPPING[ + self._config["resize_method"] + ] diff --git a/ledfx/effects/gifplayer.py b/ledfx/effects/gifplayer.py index 401154af9..6b3efff46 100644 --- a/ledfx/effects/gifplayer.py +++ b/ledfx/effects/gifplayer.py @@ -1,46 +1,26 @@ import logging import os -from enum import Enum import voluptuous as vol from PIL import Image from ledfx.consts import LEDFX_ASSETS_PATH +from ledfx.effects.gifbase import GifBase from ledfx.effects.twod import Twod from ledfx.utils import open_gif _LOGGER = logging.getLogger(__name__) -class GIFResizeMethods(Enum): - # https://pillow.readthedocs.io/en/stable/handbook/concepts.html#filters-comparison-table - NEAREST = "Fastest" - BILINEAR = "Fast" - BICUBIC = "Slow" - LANCZOS = "Slowest" - - -class GifPlayer(Twod): +class GifPlayer(Twod, GifBase): NAME = "GIF Player" CATEGORY = "Matrix" HIDDEN_KEYS = Twod.HIDDEN_KEYS + ["gradient", "background"] ADVANCED_KEYS = Twod.ADVANCED_KEYS + ["blur", "resize_method"] DEFAULT_GIF_PATH = f"{os.path.join(LEDFX_ASSETS_PATH, 'animated.gif')}" - RESIZE_METHOD_MAPPING = { - GIFResizeMethods.NEAREST.value: Image.NEAREST, - GIFResizeMethods.BILINEAR.value: Image.BILINEAR, - GIFResizeMethods.BICUBIC.value: Image.BICUBIC, - GIFResizeMethods.LANCZOS.value: Image.LANCZOS, - } + CONFIG_SCHEMA = vol.Schema( { - vol.Optional( - "resize_method", - description="What strategy to use when resizing GIF", - default=GIFResizeMethods.BICUBIC.value, - ): vol.In( - [resize_method.value for resize_method in GIFResizeMethods] - ), vol.Optional( "gif_path", description="Load GIF from URL/local file", @@ -64,12 +44,8 @@ def config_updated(self, config): super().config_updated(config) self.gif_fps = self._config["GIF FPS"] self.bounce = self._config["bounce"] - self.resize_method = self.RESIZE_METHOD_MAPPING[ - self._config["resize_method"] - ] self.frames = [] self.current_frame = 0 - self.init = True def audio_data_updated(self, data): diff --git a/ledfx/effects/keybeat2d.py b/ledfx/effects/keybeat2d.py index 51c989ed5..5af44b67a 100644 --- a/ledfx/effects/keybeat2d.py +++ b/ledfx/effects/keybeat2d.py @@ -1,12 +1,11 @@ import logging import os -import PIL.Image as Image import PIL.ImageSequence as ImageSequence import voluptuous as vol from ledfx.consts import LEDFX_ASSETS_PATH -from ledfx.effects.gradient import GradientEffect +from ledfx.effects.gifbase import GifBase from ledfx.effects.twod import Twod from ledfx.utils import ( extract_positive_integers, @@ -18,15 +17,18 @@ _LOGGER = logging.getLogger(__name__) -class Keybeat2d(Twod, GradientEffect): +class Keybeat2d(Twod, GifBase): NAME = "Keybeat2d" CATEGORY = "Matrix" HIDDEN_KEYS = Twod.HIDDEN_KEYS + [ "background_color", - "gradient_roll", - "gradient", ] - ADVANCED_KEYS = Twod.ADVANCED_KEYS + ["diag2", "fake_beat", "pp skip"] + ADVANCED_KEYS = Twod.ADVANCED_KEYS + [ + "diag2", + "fake_beat", + "pp skip", + "resize_method", + ] CONFIG_SCHEMA = vol.Schema( { @@ -316,7 +318,9 @@ def do_once(self): stretch_height = max(1, stretch_height) self.frames.append( - frame.resize((stretch_width, stretch_height), Image.BICUBIC) + frame.resize( + (stretch_width, stretch_height), self.resize_method + ) ) self.offset_x = int( @@ -333,7 +337,7 @@ def do_once(self): self.beat_times = [] # rolling window of beat timestamps self.beat_f_times = [] # rolling windows of frame info - self.begin = self.current_time # used for seconds running total + self.begin_time = self.current_time self.last_beat_t = self.current_time @@ -386,9 +390,10 @@ def overlay(self, beat_kick, skip_beat): break # if we have not reached a 60 second window yet, then gestimate bpm - passed = self.current_time - self.begin + passed = self.current_time - self.begin_time self.bpm = len(self.beat_times) - if passed < 60.0: + + if passed > 0 and passed < 60.0: self.bpm *= 60 / passed color = (255, 0, 255) else: diff --git a/ledfx/effects/template2d.py b/ledfx/effects/template2d.py index 3b7baad1c..6dbd012ae 100644 --- a/ledfx/effects/template2d.py +++ b/ledfx/effects/template2d.py @@ -2,7 +2,6 @@ import voluptuous as vol -from ledfx.effects.gradient import GradientEffect from ledfx.effects.twod import Twod _LOGGER = logging.getLogger(__name__) @@ -11,7 +10,7 @@ # Anywhere you see template, replace it with your own class reference / name -class Template2d(Twod, GradientEffect): +class Template2d(Twod): NAME = "Template2d" CATEGORY = "Matrix" # add keys you want hidden or in advanced here diff --git a/ledfx/mdns_manager.py b/ledfx/mdns_manager.py index 51c84f2e7..b0de1910c 100644 --- a/ledfx/mdns_manager.py +++ b/ledfx/mdns_manager.py @@ -1,6 +1,6 @@ import logging -from zeroconf import Zeroconf, ServiceStateChange +from zeroconf import ServiceStateChange, Zeroconf from zeroconf.asyncio import ( AsyncServiceBrowser, AsyncServiceInfo,