Skip to content

Timed animation #67

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions adafruit_led_animation/animation/volume.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# SPDX-FileCopyrightText: 2020 Gamblor21
#
# SPDX-License-Identifier: MIT
"""
`adafruit_led_animation.animation.volume`
================================================================================
Volume animation for CircuitPython helper library for LED animations.
* Author(s): Mark Komus
Implementation Notes
--------------------
**Hardware:**
* `Adafruit NeoPixels <https://www.adafruit.com/category/168>`_
* `Adafruit DotStars <https://www.adafruit.com/category/885>`_
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
https://circuitpython.org/downloads
"""

from adafruit_led_animation.animation import Animation


def map_range(x, in_min, in_max, out_min, out_max):
"""
Maps a number from one range to another.
:return: Returns value mapped to new range
:rtype: float
"""
mapped = (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
if out_min <= out_max:
return max(min(mapped, out_max), out_min)

return min(max(mapped, out_max), out_min)


class Volume(Animation):
"""
Animate the brightness and number of pixels based on volume.
:param pixel_object: The initialised LED object.
:param float speed: Animation update speed in seconds, e.g. ``0.1``.
:param brightest_color: Color at max volume ``(r, g, b)`` tuple, or ``0x000000`` hex format
:param decoder: a MP3Decoder object that the volume will be taken from
:param float max_volume: what volume is considered maximum where everything is lit up
"""

# pylint: disable=too-many-arguments
def __init__(
self, pixel_object, speed, brightest_color, decoder, max_volume=500, name=None
):
self._decoder = decoder
self._num_pixels = len(pixel_object)
self._max_volume = max_volume
self._brightest_color = brightest_color
super().__init__(pixel_object, speed, brightest_color, name=name)

def set_brightest_color(self, brightest_color):
"""
Animate the brightness and number of pixels based on volume.
:param brightest_color: Color at max volume ``(r, g, b)`` tuple, or ``0x000000`` hex format
"""
self._brightest_color = brightest_color

def draw(self):
red = int(
map_range(
self._decoder.rms_level,
0,
self._max_volume,
0,
self._brightest_color[0],
)
)
green = int(
map_range(
self._decoder.rms_level,
0,
self._max_volume,
0,
self._brightest_color[1],
)
)
blue = int(
map_range(
self._decoder.rms_level,
0,
self._max_volume,
0,
self._brightest_color[2],
)
)

lit_pixels = int(
map_range(self._decoder.rms_level, 0, self._max_volume, 0, self._num_pixels)
)
if lit_pixels > self._num_pixels:
lit_pixels = self._num_pixels

self.pixel_object[0:lit_pixels] = [(red, green, blue)] * lit_pixels
self.pixel_object[lit_pixels : self._num_pixels] = [(0, 0, 0)] * (
self._num_pixels - lit_pixels
)
84 changes: 84 additions & 0 deletions adafruit_led_animation/timedsequence.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# SPDX-FileCopyrightText: 2020 Gamblor21
#
# SPDX-License-Identifier: MIT
"""
`adafruit_led_animation.timedsequence`
================================================================================

Animation timed sequence helper for CircuitPython helper library for LED animations.


* Author(s): Mark Komus

Implementation Notes
--------------------

**Hardware:**

* `Adafruit NeoPixels <https://www.adafruit.com/category/168>`_
* `Adafruit DotStars <https://www.adafruit.com/category/885>`_

**Software and Dependencies:**

* Adafruit CircuitPython firmware for the supported boards:
https://circuitpython.org/downloads

"""

from adafruit_led_animation.sequence import AnimationSequence
from . import MS_PER_SECOND


class TimedAnimationSequence(AnimationSequence):
"""
A sequence of Animations to run in succession, each animation running for an
individual amount of time.
:param members: The animation objects or groups followed by how long the animation
should run in seconds.
:param bool auto_clear: Clear the pixels between animations. If ``True``, the current animation
will be cleared from the pixels before the next one starts.
Defaults to ``False``.
:param bool random_order: Activate the animations in a random order. Defaults to ``False``.
:param bool auto_reset: Automatically call reset() on animations when changing animations.
.. code-block:: python
import board
import neopixel
from adafruit_led_animation.timedsequence import TimedAnimationSequence
import adafruit_led_animation.animation.comet as comet_animation
import adafruit_led_animation.animation.sparkle as sparkle_animation
import adafruit_led_animation.animation.blink as blink_animation
import adafruit_led_animation.color as color
strip_pixels = neopixel.NeoPixel(board.A1, 30, brightness=1, auto_write=False)
blink = blink_animation.Blink(strip_pixels, 0.2, color.RED)
comet = comet_animation.Comet(strip_pixels, 0.1, color.BLUE)
sparkle = sparkle_animation.Sparkle(strip_pixels, 0.05, color.GREEN)
animations = TimedAnimationSequence(blink, 5, comet, 3, sparkle, 7)
while True:
animations.animate()
"""

# pylint: disable=too-many-instance-attributes
def __init__(
self, *members, auto_clear=True, random_order=False, auto_reset=False, name=None
):
self._animation_members = []
self._animation_timings = []
for x, item in enumerate(members):
if not x % 2:
self._animation_members.append(item)
else:
self._animation_timings.append(item)

super().__init__(
*self._animation_members,
auto_clear=auto_clear,
random_order=random_order,
auto_reset=auto_reset,
advance_on_cycle_complete=False,
name=name,
)
self._advance_interval = self._animation_timings[self._current] * MS_PER_SECOND

def activate(self, index):
super().activate(index)
self._advance_interval = self._animation_timings[self._current] * MS_PER_SECOND
21 changes: 21 additions & 0 deletions examples/led_animation_timedsequence.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# SPDX-FileCopyrightText: 2020 Gamblor21
#
# SPDX-License-Identifier: MIT
"""
Example for TimedSequence
"""
import board
import neopixel
from adafruit_led_animation.timedsequence import TimedAnimationSequence
import adafruit_led_animation.animation.comet as comet_animation
import adafruit_led_animation.animation.sparkle as sparkle_animation
import adafruit_led_animation.animation.blink as blink_animation
from adafruit_led_animation import color

strip_pixels = neopixel.NeoPixel(board.D6, 32, brightness=0.1, auto_write=False)
blink = blink_animation.Blink(strip_pixels, 0.3, color.RED)
comet = comet_animation.Comet(strip_pixels, 0.1, color.BLUE)
sparkle = sparkle_animation.Sparkle(strip_pixels, 0.05, color.GREEN)
animations = TimedAnimationSequence(blink, 2, comet, 4, sparkle, 5)
while True:
animations.animate()
34 changes: 34 additions & 0 deletions examples/led_animation_volume.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# SPDX-FileCopyrightText: 2023 Tim Cocks
#
# SPDX-License-Identifier: MIT

"""Volume Animation Example"""
import board
from audiomp3 import MP3Decoder
import neopixel
from adafruit_led_animation.animation import volume

try:
from audioio import AudioOut
except ImportError:
try:
from audiopwmio import PWMAudioOut as AudioOut
except ImportError:
pass # not always supported by every board!

# Fill in your own MP3 file or use the one from the learn guide:
# https://learn.adafruit.com/circuitpython-essentials/circuitpython-mp3-audio#installing-project-code-3067700
mp3file = "happy.mp3"
with open(mp3file, "rb") as mp3:
decoder = MP3Decoder(mp3)
audio = AudioOut(board.SPEAKER)

strip_pixels = neopixel.NeoPixel(board.D4, 30, brightness=0.1, auto_write=False)
volume_anim = volume.Volume(strip_pixels, 0.3, (0, 255, 0), decoder, 400)

while True:
audio.play(decoder)
print("playing", mp3file)

while audio.playing:
volume_anim.animate()