39#ifndef SBK_BARDRIVE_QUEUE_CAPACITY
40#define SBK_BARDRIVE_QUEUE_CAPACITY 4
43#if SBK_BARDRIVE_QUEUE_CAPACITY < 1 || SBK_BARDRIVE_QUEUE_CAPACITY > 255
44#error "SBK_BARDRIVE_QUEUE_CAPACITY must be between 1 and 255"
57template <
typename BarMeterT>
93 bool update(uint32_t syncTime = millis())
310 const uint8_t previousIndex =
336 const uint8_t previousIndex =
339 entry =
_queue[previousIndex];
578 const uint8_t previousIndex =
709 return blinkPixel(index, interval, interval, blinkCount);
886 return emptyDownIntv(duration / steps, maxPercent, minPercent);
1017 uint16_t emptyIntv = fillIntv;
1020 fillIntv =
_maxValue(5, duration) / (2 * steps);
1021 emptyIntv = fillIntv;
1025 emptyIntv =
_maxValue(5, duration - fillIntv * steps) / steps;
1105 uint16_t emptyIntv = fillIntv;
1108 fillIntv =
_maxValue(5, duration) / (2 * steps);
1109 emptyIntv = fillIntv;
1113 emptyIntv =
_maxValue(5, duration - fillIntv * steps) / steps;
1195 uint16_t emptyIntv = fillIntv;
1198 fillIntv =
_maxValue(5, duration) / (2 * steps);
1199 emptyIntv = fillIntv;
1203 emptyIntv =
_maxValue(5, duration - fillIntv * steps) / steps;
1287 uint16_t emptyIntv = fillIntv;
1290 fillIntv =
_maxValue(5, duration) / (2 * steps);
1291 emptyIntv = fillIntv;
1295 emptyIntv =
_maxValue(5, duration - fillIntv * steps) / steps;
1967 if (resetRuntimeState)
1977 : previousRenderLogic;
1996 if (resetRuntimeState)
2042 const uint16_t requestedCapacity =
static_cast<uint16_t
>(
_segmentCapacity) + 2U;
2045 const uint8_t randomOrderBlocks =
2048 if (workspaceBlocks > 0)
2065 for (uint8_t i = 0; i < blockCapacity; ++i)
2072 template <
typename A,
typename B>
2073 static auto _minValue(A a, B b) ->
decltype(
true ? A() : B())
2075 return a < b ? a : b;
2078 template <
typename A,
typename B>
2079 static auto _maxValue(A a, B b) ->
decltype(
true ? A() : B())
2081 return a > b ? a : b;
2086 minP = constrain(minP, 0, 100);
2087 maxP = constrain(maxP, 0, 100);
2112 uint8_t minP = minPercPtr ? *minPercPtr : 0;
2113 uint8_t maxP = maxPercPtr ? *maxPercPtr : 100;
2134 return abs((half - 1) - pixel);
2138 if (minVal > maxVal)
2140 uint16_t temp = maxVal;
2144 if (minVal == maxVal)
2148 maxVal = minVal + 1;
2156 static inline uint8_t
_getMappedSignal(uint16_t sig, uint16_t minM, uint16_t maxM, uint8_t minR, uint8_t maxR)
2158 uint8_t mapped = map(sig, minM, maxM, minR, maxR);
2159 return constrain(mapped, minR, maxR);
2167 for (uint8_t i = 0; i <
_segsNum; i++)
2190 const uint8_t index =
_param1;
2191 const uint8_t blinkCount =
_param2;
2216 return blinkCount > 0 &&
_counter1 >= blinkCount;
2239 for (uint8_t i = 0; i <
_segsNum; ++i)
2250 for (uint8_t i = 0; i <
_segsNum; ++i)
2335 const uint8_t center =
_segsNum / 2;
2350 for (uint8_t i = 0; i < center; ++i)
2370 for (uint8_t i = 0; i < center; ++i)
2461#define MIN_BASE_LEVEL _param2
2462#define MIN_PEAK_LEVEL _param3
2463#define PEAK_HOLD_TIME _param4
2464#define bpmPtr _liveBpmPtr()
2465#define currentLevel _ledTracker1
2466#define peakLevel _ledTracker2
2467#define beat _updateIntv1
2468#define lastBeat _lastUpdate1
2469#define lastRandomUpdate _lastUpdate2
2470#define prevPeakUpdate _lastUpdate3
2473 static int8_t randomOffset;
2474 static bool isPeak =
false;
2509 randomOffset = random(-4, 4);
2513 finalLevel = constrain(finalLevel, 0,
_segsNum);
2532 for (uint8_t i = 0; i <
_segsNum; i++)
2552#undef MIN_BASE_LEVEL
2553#undef MIN_PEAK_LEVEL
2554#undef PEAK_HOLD_TIME
2560#undef lastRandomUpdate
2561#undef prevPeakUpdate
2563#define blockLength _param1
2564#define blockSpacing _param2
2565#define requestedNumBlocks _param3
2566#define maxBlocks _param4
2567#define emitIndex _param5
2568#define emittedBlocksCount _counter1
2569#define emitCooldown _counter2
2631 return (range - 1) - pos + (blockL - 1);
2638 int8_t closestSwp = -127;
2662 if (closestSwp == -127 || swp < closestSwp)
2666 if (closestSwp >= 0)
2667 return (emitInterval - 1) - closestSwp;
2674 const uint8_t center =
_segsNum / 2;
2719 for (uint8_t j = 0; j < pixelsVisible; ++j)
2727 int8_t idx = tailOffset;
2731 int8_t mirrorIdx =
_segsNum - 1 - idx;
2737 if (mirrorIdx != idx && mirrorIdx >= 0 && mirrorIdx <
_segsNum)
2801 int8_t idx = tailOffset;
2818#define stackLevel _ledTracker1
2822 bool hasActive =
false;
2916 if (clearPos >= 0 && clearPos <
_segsNum)
2957 for (int8_t i = 0; i <
stackLevel - blockInterval; ++i)
2967 for (uint8_t i = 0; i <
stackLevel - blockInterval; i++)
2991#undef requestedNumBlocks
2994#undef emittedBlocksCount
2997#define smoothingFactor _param1
3033 for (uint8_t i = 0; i <
_segsNum; i++)
3077 for (uint8_t i = 0; i <
_segsNum; i++)
3083 if (pointer < avg && pointer > 0)
3086 if (pointer < avg - 2)
3143 uint8_t level2 = level1;
3147 for (uint8_t i = 0; i <
_segsNum; i++)
3159#define currentLevel _ledTracker1
3160#define peakLevel _ledTracker3
3161#define baseUpdate _updateIntv1
3162#define lastBaseUpdate _lastUpdate1
3163#define peakHoldTime _updateIntv3
3164#define lastPeakUpdate _lastUpdate3
3218 for (uint8_t i = 0; i <
_segsNum; i++)
3234#undef lastBaseUpdate
3236#undef lastPeakUpdate
3238#undef smoothingFactor
3258 for (uint8_t i = 0; i <
_segsNum; ++i)
3261 for (uint8_t i =
_segsNum - 1; i > 0; --i)
3263 uint8_t j = random(0, i + 1);
3264 uint8_t tmp = pixelOrder[i];
3265 pixelOrder[i] = pixelOrder[j];
3266 pixelOrder[j] = tmp;
3279 uint8_t retries = 0;
3283 bool currentState =
_barMeter.getPixelState(seg);
#define emittedBlocksCount
#define SBK_BARDRIVE_QUEUE_CAPACITY
#define requestedNumBlocks
bool isNonInvertingLogicAnim()
Return true if the current animation does not support logic inversion.
SBK_BarMeterAnimations & fillUpIntv(uint16_t updateIntv, const uint8_t *maxPercentPtr, const uint8_t *minPercentPtr=nullptr)
Start animation that fills the bar upwards at a fixed interval with live percent tracking.
bool _followDualSignalCenterMirror()
SBK_BarMeterAnimations & beatPulse(uint8_t bpm=116)
Start a beat pulse animation synchronized to a constant BPM.
uint32_t _animationDuration
SBK_BarMeterAnimations & bounceFillUpIntv(uint16_t fillIntv, uint16_t emptyIntv, const uint8_t *maxPercentPtr, const uint8_t *minPercentPtr=nullptr)
Start animation that fills/empties (bounces) bar upward with live range.
SBK_BarMeterAnimations & fillDownDur(uint16_t duration, uint8_t maxPercent=100, uint8_t minPercent=0)
Start animation that fills the bar downwards over a specified duration.
SBK_BarMeterAnimations & fillUpIntv(uint16_t updateIntv, uint8_t maxPercent=100, uint8_t minPercent=0)
Start animation that fills the bar upwards at a fixed interval.
void _emitBlock(int8_t pos)
bool _prevAnimRenderLogic
SBK_BarMeterAnimations & emptyUpIntv(uint16_t updateIntv, const uint8_t *maxPercentPtr, const uint8_t *minPercentPtr=nullptr)
Start animation that empties the bar from bottom to top at fixed intervals with live range.
SBK_BarMeterAnimations & loop()
Set animation to automatically loop when complete.
uint8_t currentQueueIndex() const
Return the physical queue slot currently playing, or NO_QUEUE_INDEX.
SBK_BarMeterAnimations & bounceFillFromEdgesDur(uint16_t duration, uint8_t maxPercent=100, uint8_t minPercent=0, uint16_t fillIntv=0)
Bounce fill from both edges inward with fixed range.
SBK_BarMeterAnimations & waitTrailingSpace(bool enabled=true)
Optionally wait one block spacing after the final block clears.
static int8_t _calculateSwitchPosition(int8_t pos, uint8_t blockL, uint8_t range)
SBK_BarMeterAnimations & setDir(bool newDirection)
Explicitly set the animation rendering direction.
void _initializeStorage()
SBK_BarMeterAnimations & bounceFillUpDur(uint16_t duration, uint8_t maxPercent=100, uint8_t minPercent=0, uint16_t fillIntv=0)
Start animation that fills/empties (bounces) bar upward with fixed range.
SBK_BarMeterAnimations & beatPulse(uint8_t *bpmPtr)
Start a beat pulse animation synchronized to a live BPM value.
SBK_BarMeterAnimations(BarMeterT &barMeter)
Construct an animation controller linked to a bar meter.
SBK_BarMeterAnimations & fillDownIntv(uint16_t updateIntv, uint8_t maxPercent=100, uint8_t minPercent=0)
Start animation that fills the bar downwards at a fixed interval.
SBK_BarMeterAnimations & toggleLogic()
Toggle rendering logic (inverted vs normal), example fill logic become empty logic.
bool _followSignalFloatingPeak()
SBK_BarMeterAnimations & loopQueue()
Repeat the entire queue after its final entry completes.
SBK_BarMeterAnimations & followSignalWithPointer(const uint16_t *sigPtr, uint16_t updateIntv=100, uint16_t minMap=0, uint16_t maxMap=1023, uint8_t smoothingFactor=30, uint16_t samplingIntv=5)
Follow signal with smoothing and display a pointer.
SBK_BarMeterAnimations & toggleDir()
Toggle the current animation rendering direction.
SBK_BarMeterAnimations & emptyDownIntv(uint16_t updateIntv, uint8_t maxPercent=100, uint8_t minPercent=0)
Start animation that empties the bar from top to bottom at fixed intervals.
void _loadQueueEntry(const QueueEntry &entry, bool forceReset=false)
const uint16_t * _signalPtr1() const
SBK_BarMeterAnimations & reverseDir()
Reverse the rendering direction compared to the original one.
void _mapMinMaxTracker(uint8_t minP, uint8_t maxP, uint8_t minR, uint8_t maxR)
SBK_BarMeterAnimations & pause(uint32_t syncTime=millis())
Freeze animation progression and all queue/animation timers.
void _mapMinMaxTrackerFromPtr(const uint8_t *minPercPtr, const uint8_t *maxPercPtr, int8_t minR, uint8_t maxR)
SBK_BarMeterAnimations & bounceFillDownDur(uint16_t duration, uint8_t maxPercent=100, uint8_t minPercent=0, uint16_t fillIntv=0)
Start animation that fills/empties (bounces) bar downward.
SBK_BarMeterAnimations & setUpdateInterval(uint16_t interval)
Change the primary update interval without restarting the animation.
SBK_BarMeterAnimations & followSignalSmooth(const uint16_t *sigPtr, uint16_t updateIntv=100, uint16_t minMap=0, uint16_t maxMap=1023, uint8_t smoothingFactor=30, uint16_t samplingIntv=5)
Follow analog signal with smoothing for fill animation.
static constexpr uint8_t MAX_BLOCK_CAPACITY
const uint8_t * _liveBpmPtr() const
SBK_BarMeterAnimations & followSignalFloatingPeak(const uint16_t *sigPtr, uint8_t peakHoldTime=20, uint16_t updateIntv=100, uint16_t minMap=0, uint16_t maxMap=1023, uint8_t smoothingFactor=30, uint16_t samplingIntv=5)
Follow an analog signal with smoothing and floating peak indicator.
static auto _minValue(A a, B b) -> decltype(true ? A() :B())
bool _animRenderLogicIsInverted
bool _trailingSpacePending
const uint16_t * _signalPtr2() const
SBK_BarMeterAnimations & setAll(bool onff)
Set all pixels to the specified state.
SBK_BarMeterAnimations & downStackingBlocks(uint16_t intv=50, uint8_t blockLength=1, uint8_t blockSpacing=0)
Drop blocks from top and stack from bottom up.
bool _isNonInvertingLogicAnim
void _resetBlocks(uint8_t &blockCapacity)
uint8_t _corrPixelToDirForHalfRange(uint8_t pixel)
const uint8_t * _percentMaxPtr() const
SBK_BarMeterAnimations & emptyDownDur(uint16_t duration, uint8_t maxPercent=100, uint8_t minPercent=0)
Start animation that empties the bar from top to bottom over a duration.
bool _queueEntryTimingPending
SBK_BarMeterAnimations & blinkPixel(uint8_t index, uint16_t interval=500, uint8_t blinkCount=0)
Blink one pixel with equal ON and OFF intervals.
bool queueOverflowed() const
Return true if an enqueue operation exceeded the configured capacity.
static constexpr uint8_t QUEUE_CAPACITY
SBK_BarMeterAnimations & setLogic(bool newLogic)
Set rendering logic (true = inverted logic, false = normal logic), example fill logic become empty lo...
SBK_BarMeterAnimations & downUnstackingBlocks(uint16_t intv=50, uint8_t blockLength=1, uint8_t blockSpacing=0)
Drop blocks from top and unstack from bottom up.
bool isQueueRunning() const
Return true while an animation queue is being processed.
void _startNextQueuedAnimation(bool forceReset=false)
SBK_BarMeterAnimations & resetDir()
Reset direction to the original setting.
SBK_BarMeterAnimations & setAllOff()
Set all pixels OFF.
SBK_BarMeterAnimations & animInit()
Mark animation as ready to reinitialize in next update cycle.
bool _emittingBlocksEnabled
SBK_BarMeterAnimations & randomEmpty(uint16_t interval=30)
Randomly turn off pixels until the bar is empty.
bool isQueueIndexPlaying(uint8_t index) const
Return true when the requested physical queue slot is currently playing.
SBK_BarMeterAnimations & stopBlockEmission()
Stop emitting new blocks during compatible block animations.
SBK_BarMeterAnimations & blinkPixel(uint8_t index, uint16_t onInterval, uint16_t offInterval, uint8_t blinkCount)
Blink one pixel with independent ON and OFF intervals.
uint32_t _queueEntryStartedAt
SBK_BarMeterAnimations & upStackingBlocks(uint16_t intv=50, uint8_t blockLength=1, uint8_t blockSpacing=0)
Launch blocks from bottom and stack at the top.
bool isLogicInverted()
Returns true if current logic is different from original logic.
SBK_BarMeterAnimations & enqueue()
Add the currently configured animation to the fixed-capacity queue.
SBK_BarMeterAnimations & enqueueReverseAnim()
Queue a state-preserving logic reversal of the preceding entry.
SBK_BarMeterAnimations & followDualSignalFromCenter(const uint16_t *sig1Ptr, uint16_t updateIntv=100, const uint16_t *sig2Ptr=nullptr, uint16_t minMap=0, uint16_t maxMap=1023, uint8_t smoothingFactor=30, uint16_t samplingIntv=5)
Smoothly fills the lower half and upper half of the bar meter independently from center,...
SBK_BarMeterAnimations & explodingBlocks(uint16_t intv=50, uint8_t blockLength=2, uint8_t blockSpacing=1, uint8_t numBlocks=0)
Emit mirrored blocks from center outward.
uint32_t _blockEmissionStopAfter
bool animPendingLoop()
Detect whether animation has completed and is about to loop.
void _captureQueueEntry(QueueEntry &entry, bool resetRuntimeState, uint32_t duration)
static void _correctSwapOrEqualMinMax(uint16_t &minVal, uint16_t &maxVal)
bool isBlockEmissionEnabled() const
Query if block emission is enabled.
SBK_BarMeterAnimations & noLoop()
Disable auto-looping.
SBK_BarMeterAnimations & emptyDownIntv(uint16_t updateIntv, const uint8_t *maxPercentPtr, const uint8_t *minPercentPtr=nullptr)
Start animation that empties the bar from top to bottom at fixed intervals with live range.
SBK_BarMeterAnimations & stop()
Terminate the animation, loop, and queue, then clear mapped pixels.
int8_t _calculateSwitchedEmitTickCounter(uint8_t range)
SBK_BarMeterAnimations & upUnstackingBlocks(uint16_t intv=50, uint8_t blockLength=1, uint8_t blockSpacing=0)
Launch blocks upward and unstack from top.
SBK_BarMeterAnimations & wait(uint16_t duration)
Wait without blocking or changing pixel states; waits never loop.
uint8_t _corrPixelToDir(uint8_t pixel)
SBK_BarMeterAnimations & bounceFillFromCenterIntv(uint16_t fillIntv=25, uint16_t emptyIntv=25, uint8_t maxPercent=100, uint8_t minPercent=0)
Bounce fill from center outward with fixed range.
bool _fillFromOrEmptyToCenter()
SBK_BarMeterAnimations & bounceFillFromCenterIntv(uint16_t fillIntv, uint16_t emptyIntv, const uint8_t *maxPercentPtr, const uint8_t *minPercentPtr=nullptr)
Bounce fill from center outward with live percent range tracking.
bool _followSignalWithPointer()
const uint8_t * _percentMinPtr() const
bool update(uint32_t syncTime=millis())
Advance the animation logic based on the current millis().
SBK_BarMeterAnimations & collidingBlocks(uint16_t intv=50, uint8_t blockLength=2, uint8_t blockSpacing=1, uint8_t numBlocks=0)
Emit mirrored blocks from edge to center.
uint8_t _currentQueueIndex
~SBK_BarMeterAnimations()
bool _AnimInitLogicIsInverted
QueueEntry _queue[QUEUE_CAPACITY]
SBK_BarMeterAnimations & noLoopQueue()
Disable repetition; finish the current queue pass before stopping.
SBK_BarMeterAnimations & emptyUpDur(uint16_t duration, uint8_t maxPercent=100, uint8_t minPercent=0)
Start animation that empties the bar from bottom to top over a duration.
uint8_t _queueStoredCount
SBK_BarMeterAnimations & resetLogic()
Reset logic to initial (default) value.
bool isLoopEnabled() const
Query if animation loop is enabled.
void setSegsNum(uint8_t n)
Set the total number of segments the animation logic should handle.
SBK_BarMeterAnimations & startQueue()
Start queued playback using the current queue-loop setting.
static void _normalizePercentRange(uint8_t &minP, uint8_t &maxP)
SBK_BarMeterAnimations & setAllOn()
Set all pixels ON.
SBK_BarMeterAnimations & stopBlockEmissionAfter(uint32_t duration)
Stop new block emission after an animation has run for a duration.
bool(SBK_BarMeterAnimations::*)() AnimUpdateFn
AnimUpdateFn _currentFunc
bool isRunning() const
Query if animation is currently active.
SBK_BarMeterAnimations & bounceFillDownIntv(uint16_t fillIntv=10, uint16_t emptyIntv=10, uint8_t maxPercent=100, uint8_t minPercent=0)
Start downwardfill/empty (bounce) with fixed percent range.
SBK_BarMeterAnimations & invertLogic()
Reverse logic compared to initial state Logic refer to behavior, example : fill/empty,...
bool _bounceFillHalfRangeMirrorCenter()
SBK_BarMeterAnimations & scrollingDownBlocks(uint16_t intv=50, uint8_t blockLength=2, uint8_t blockSpacing=1, uint8_t numBlocks=0)
Scroll blocks downward.
uint32_t _activeBlockEmissionStopAfter
SBK_BarMeterAnimations & emptyUpIntv(uint16_t updateIntv, uint8_t maxPercent=100, uint8_t minPercent=0)
Start animation that empties the bar from bottom to top at fixed intervals.
SBK_BarMeterAnimations & bounceFillDownIntv(uint16_t fillIntv, uint16_t emptyIntv, const uint8_t *maxPercentPtr, const uint8_t *minPercentPtr=nullptr)
Start downward fill/empty (bounce) with live percent range tracking.
SBK_BarMeterAnimations & forTime(uint32_t duration)
Limit a direct or queued animation to a maximum run time.
SBK_BarMeterAnimations & bounceFillFromCenterDur(uint16_t duration, uint8_t maxPercent=100, uint8_t minPercent=0, uint16_t fillIntv=0)
Bounce fill from center outward with fixed range.
SBK_BarMeterAnimations & skipCurrent()
Abandon the active animation and immediately start the next queue entry.
Block * _animationWorkspace
SBK_BarMeterAnimations & fillDownIntv(uint16_t updateIntv, const uint8_t *maxPercentPtr, const uint8_t *minPercentPtr=nullptr)
Start animation that fills the bar downwards at a fixed interval with live percent tracking.
static uint8_t _getMappedSignal(uint16_t sig, uint16_t minM, uint16_t maxM, uint8_t minR, uint8_t maxR)
bool _AnimInitDirIsReversed
SBK_BarMeterAnimations & resumeBlockEmission()
Resume emitting new blocks during compatible block animations.
SBK_BarMeterAnimations & clearQueue()
Discard the queue and disable queue looping without stopping the current animation.
bool _randomPixelUpdater()
static auto _maxValue(A a, B b) -> decltype(true ? A() :B())
SBK_BarMeterAnimations & randomFill(uint16_t interval=30)
Randomly light up pixels until the bar is full.
uint8_t queuedAnimations() const
Return the number of animations waiting behind the active one.
SBK_BarMeterAnimations & bounceFillUpIntv(uint16_t fillIntv=10, uint16_t emptyIntv=10, uint8_t maxPercent=100, uint8_t minPercent=0)
Start animation that fills/empties (bounces) bar upward with fixed range.
SBK_BarMeterAnimations & fillUpDur(uint16_t duration, uint8_t maxPercent=100, uint8_t minPercent=0)
Start animation that fills the bar upwards over a specified duration.
SBK_BarMeterAnimations & bounceFillFromEdgesIntv(uint16_t fillIntv, uint16_t emptyIntv, const uint8_t *maxPercentPtr, const uint8_t *minPercentPtr=nullptr)
Bounce fill from both edges inward with live percent range tracking.
static constexpr uint8_t NO_QUEUE_INDEX
SBK_BarMeterAnimations & scrollingUpBlocks(uint16_t intv=50, uint8_t blockLength=2, uint8_t blockSpacing=1, uint8_t numBlocks=0)
Scroll blocks upward.
SBK_BarMeterAnimations & resume(uint32_t syncTime=millis())
Resume with the same playback time remaining as when paused.
bool _followSignalSmooth()
SBK_BarMeterAnimations & enqueueFor(uint32_t duration)
Queue the configured animation for a fixed amount of time.
SBK_BarMeterAnimations & followDualSignalFromEdges(const uint16_t *sig1Ptr, uint16_t updateIntv=100, const uint16_t *sig2Ptr=nullptr, uint16_t minMap=0, uint16_t maxMap=1023, uint8_t smoothingFactor=30, uint16_t samplingIntv=5)
Smoothly fills the lower half and upper half of the bar meter independently from center,...
bool _animRenderDirIsReversed
bool isDirectionReversed()
Returns true if direction is reversed compared to the original.
uint32_t _queueEntryDuration
SBK_BarMeterAnimations & bounceFillFromEdgesIntv(uint16_t fillIntv=25, uint16_t emptyIntv=25, uint8_t maxPercent=100, uint8_t minPercent=0)
Bounce fill from both edges inward with fix range.
bool isPaused() const
Query if animation is paused.
bool animInitLogicIsInverted
bool isNonInvertingLogicAnim
uint32_t blockEmissionStopAfter
bool animInitDirIsReversed
bool animRenderDirIsReversed
bool animRenderLogicIsInverted
bool emittingBlocksEnabled