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())
485 return blinkPixel(index, interval, interval, blinkCount);
499 _updateIntv1 = max(
static_cast<uint16_t
>(1), onInterval);
500 _updateIntv2 = max(
static_cast<uint16_t
>(1), offInterval);
662 return emptyDownIntv(duration / steps, maxPercent, minPercent);
793 uint16_t emptyIntv = fillIntv;
796 fillIntv = max(5, duration) / (2 * steps);
797 emptyIntv = fillIntv;
801 emptyIntv = max(5, duration - fillIntv * steps) / steps;
881 uint16_t emptyIntv = fillIntv;
884 fillIntv = max(5, duration) / (2 * steps);
885 emptyIntv = fillIntv;
889 emptyIntv = max(5, duration - fillIntv * steps) / steps;
971 uint16_t emptyIntv = fillIntv;
974 fillIntv = max(5, duration) / (2 * steps);
975 emptyIntv = fillIntv;
979 emptyIntv = max(5, duration - fillIntv * steps) / steps;
1063 uint16_t emptyIntv = fillIntv;
1066 fillIntv = max(5, duration) / (2 * steps);
1067 emptyIntv = fillIntv;
1071 emptyIntv = max(5, duration - fillIntv * steps) / steps;
1759 const uint16_t requestedCapacity =
static_cast<uint16_t
>(
_segmentCapacity) + 2U;
1762 const uint8_t randomOrderBlocks =
1764 const uint8_t workspaceBlocks = max(
_blockCapacity, randomOrderBlocks);
1765 if (workspaceBlocks > 0)
1782 for (uint8_t i = 0; i < blockCapacity; ++i)
1789 minP = constrain(minP, 0, 100);
1790 maxP = constrain(maxP, 0, 100);
1815 uint8_t minP = minPercPtr ? *minPercPtr : 0;
1816 uint8_t maxP = maxPercPtr ? *maxPercPtr : 100;
1837 return abs((half - 1) - pixel);
1841 if (minVal > maxVal)
1843 uint16_t temp = maxVal;
1847 if (minVal == maxVal)
1851 maxVal = minVal + 1;
1859 static inline uint8_t
_getMappedSignal(uint16_t sig, uint16_t minM, uint16_t maxM, uint8_t minR, uint8_t maxR)
1861 uint8_t mapped = map(sig, minM, maxM, minR, maxR);
1862 return constrain(mapped, minR, maxR);
1870 for (uint8_t i = 0; i <
_segsNum; i++)
1893 const uint8_t index =
_param1;
1894 const uint8_t blinkCount =
_param2;
1919 return blinkCount > 0 &&
_counter1 >= blinkCount;
1942 for (uint8_t i = 0; i <
_segsNum; ++i)
1953 for (uint8_t i = 0; i <
_segsNum; ++i)
2038 const uint8_t center =
_segsNum / 2;
2053 for (uint8_t i = 0; i < center; ++i)
2073 for (uint8_t i = 0; i < center; ++i)
2152#define MIN_BASE_LEVEL _param2
2153#define MIN_PEAK_LEVEL _param3
2154#define PEAK_HOLD_TIME _param4
2155#define bpmPtr _liveBpmPtr()
2156#define currentLevel _ledTracker1
2157#define peakLevel _ledTracker2
2158#define beat _updateIntv1
2159#define lastBeat _lastUpdate1
2160#define lastRandomUpdate _lastUpdate2
2161#define prevPeakUpdate _lastUpdate3
2164 static int8_t randomOffset;
2165 static bool isPeak =
false;
2200 randomOffset = random(-4, 4);
2204 finalLevel = constrain(finalLevel, 0,
_segsNum);
2223 for (uint8_t i = 0; i <
_segsNum; i++)
2243#undef MIN_BASE_LEVEL
2244#undef MIN_PEAK_LEVEL
2245#undef PEAK_HOLD_TIME
2251#undef lastRandomUpdate
2252#undef prevPeakUpdate
2254#define blockLength _param1
2255#define blockSpacing _param2
2256#define requestedNumBlocks _param3
2257#define maxBlocks _param4
2258#define emitIndex _param5
2259#define emittedBlocksCount _counter1
2260#define emitCooldown _counter2
2296 return (range - 1) - pos + (blockL - 1);
2303 int8_t closestSwp = -127;
2327 if (closestSwp == -127 || swp < closestSwp)
2331 if (closestSwp >= 0)
2332 return (emitInterval - 1) - closestSwp;
2339 const uint8_t center =
_segsNum / 2;
2381 uint16_t clamped = max(0, (int16_t)b.
position + 1);
2382 uint8_t pixelsVisible = min(
blockLength, (uint8_t)clamped);
2383 for (uint8_t j = 0; j < pixelsVisible; ++j)
2391 int8_t idx = tailOffset;
2395 int8_t mirrorIdx =
_segsNum - 1 - idx;
2401 if (mirrorIdx != idx && mirrorIdx >= 0 && mirrorIdx <
_segsNum)
2415 bool anyActive =
false;
2479 int8_t idx = tailOffset;
2506#define stackLevel _ledTracker1
2510 bool hasActive =
false;
2604 if (clearPos >= 0 && clearPos <
_segsNum)
2645 for (int8_t i = 0; i <
stackLevel - blockInterval; ++i)
2655 for (uint8_t i = 0; i <
stackLevel - blockInterval; i++)
2679#undef requestedNumBlocks
2682#undef emittedBlocksCount
2685#define smoothingFactor _param1
2721 for (uint8_t i = 0; i <
_segsNum; i++)
2765 for (uint8_t i = 0; i <
_segsNum; i++)
2771 if (pointer < avg && pointer > 0)
2774 if (pointer < avg - 2)
2831 uint8_t level2 = level1;
2835 for (uint8_t i = 0; i <
_segsNum; i++)
2847#define currentLevel _ledTracker1
2848#define peakLevel _ledTracker3
2849#define baseUpdate _updateIntv1
2850#define lastBaseUpdate _lastUpdate1
2851#define peakHoldTime _updateIntv3
2852#define lastPeakUpdate _lastUpdate3
2906 for (uint8_t i = 0; i <
_segsNum; i++)
2922#undef lastBaseUpdate
2924#undef lastPeakUpdate
2926#undef smoothingFactor
2946 for (uint8_t i = 0; i <
_segsNum; ++i)
2949 for (uint8_t i =
_segsNum - 1; i > 0; --i)
2951 uint8_t j = random(0, i + 1);
2952 uint8_t tmp = pixelOrder[i];
2953 pixelOrder[i] = pixelOrder[j];
2954 pixelOrder[j] = tmp;
2967 uint8_t retries = 0;
2971 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.
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 & resume()
Resume animation after pause.
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.
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 & 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.
void _startNextQueuedAnimation()
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.
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)
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.
bool _animRenderLogicIsInverted
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.
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.
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.
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 & 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.
bool animPendingLoop()
Detect whether animation has completed and is about to loop.
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.
SBK_BarMeterAnimations & pause()
Pause animation progression.
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 the current pixel states.
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
void _loadQueueEntry(const QueueEntry &entry)
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 & 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.
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 the first queued animation, if any.
static void _normalizePercentRange(uint8_t &minP, uint8_t &maxP)
SBK_BarMeterAnimations & setAllOn()
Set all pixels ON.
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()
void _captureQueueEntry(QueueEntry &entry)
SBK_BarMeterAnimations & scrollingDownBlocks(uint16_t intv=50, uint8_t blockLength=2, uint8_t blockSpacing=1, uint8_t numBlocks=0)
Scroll blocks downward.
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 & 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 all pending queued animations without stopping the current animation.
bool _randomPixelUpdater()
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.
bool _followSignalSmooth()
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.
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
bool animInitDirIsReversed
bool animRenderDirIsReversed
bool animRenderLogicIsInverted
bool emittingBlocksEnabled