71 {12.0f, 50.0f}, {22.0f, 42.0f}, {22.0f, 58.0f},
72 {32.0f, 34.0f}, {32.0f, 50.0f}, {32.0f, 66.0f},
74 {50.0f, 30.0f}, {50.0f, 38.0f}, {50.0f, 46.0f},
75 {50.0f, 54.0f}, {50.0f, 62.0f}, {50.0f, 70.0f},
77 {88.0f, 50.0f}, {78.0f, 42.0f}, {78.0f, 58.0f},
78 {68.0f, 34.0f}, {68.0f, 50.0f}, {68.0f, 66.0f},
83 "HydroPack screenmap must contain every preview LED");
97 "The INMP441 sound-pressure gate warms up for two seconds of confident "
98 "beats before arming music mode. Conversation and one-off noise stay "
100 "fires the center, with stronger hits launching to both triangles.");
108#if defined(FL_IS_WASM)
109fl::UICheckbox streamDetectorFrames(
"Stream Detector Frames",
true);
137 if (!sample.isValid() || sample.pcm().empty()) {
177 const float bassAverage =
gAudio->getVibeBassAtt();
178 if (!levels.
bassSpike || bassAverage <= 0.0f) {
181 return fl::clamp((levels.
bass - bassAverage) / bassAverage, 0.0f, 1.0f);
186 if (bass <= threshold) {
189 const float intensity =
fl::clamp((bass - threshold) / threshold,
195 float decaySeconds,
float deltaSeconds) {
196 const float seconds = target > value ? attackSeconds : decaySeconds;
197 if (seconds <= 0.0f) {
200 const float amount =
fl::clamp(deltaSeconds / seconds, 0.0f, 1.0f);
201 return value + (target - value) * amount;
205 float attackSeconds,
float decaySeconds,
206 float deltaSeconds) {
218 float deltaSeconds) {
219 if (durationSeconds <= 0.0f) {
222 const float step = deltaSeconds / durationSeconds;
223 if (target > value) {
224 return fl::min(target, value + step);
226 return fl::max(target, value - step);
236 const uint8_t centerBrightness =
238 const uint8_t triangleBrightness =
240 const CRGB centerColor(0, centerBrightness / 3, centerBrightness);
241 const CRGB triangleColor(0, triangleBrightness / 3, triangleBrightness);
261#if defined(FL_IS_WASM)
262 streamDetectorFrames.setGroup(
"Debug");
268 FL_WARN(
"HydroPack: no audio processor available");
272 gAudio->setNoiseFloorTrackingEnabled(
true);
279#if defined(FL_IS_WASM)
285 if (streamDetectorFrames.value()) {
288 "HYDRO frame=%lu spl=%.1f zcf=%.3f silent=%u "
289 "beat=%.3f bpm=%.1f tempo=%.3f tempo_bpm=%.1f "
290 "vibe_bass=%.3f vibe_att=%.3f vibe_conf=%.3f spike=%u "
291 "bass_raw=%.3f gate=%u\\n",
293 sample.zcf(),
gAudio->isSilent() ? 1U : 0U,
323 static bool firstFrame =
true;
325 const uint32_t deltaMs = firstFrame ? 0 : (now - lastMs);
337 const float deltaSeconds = float(deltaMs) * 0.001f;
fl::UIDescription description("Demo of the Animatrix effects. @author of fx is StefanPetrick")
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_GLOBAL_CONSTRUCTORS CFastLED FastLED
Global LED strip management instance.
static Config CreateInmp441(int pin_ws, int pin_sd, int pin_clk, AudioChannel channel, u16 sample_rate=44100ul, int i2s_num=0) FL_NO_EXCEPT
fl::UIButton trigger("Trigger")
#define EVERY_N_MILLIS(N)
Checks whether to execute a block of code every N milliseconds.
constexpr float kDefaultMinimumBeatConfidence
constexpr uint32_t kMaximumMusicBeatGapMs
fl::UISlider stageThresholdDbSpl("Minimum Music Level (dB SPL)", kDefaultStageThresholdDbSpl, 60.0f, 105.0f, 1.0f)
CRGB previewLeds[kPreviewLedCount]
float gCenterEnvelopeStage
float gTriangleEnvelopeStage
uint8_t toByte(float value)
constexpr uint8_t kHydroPackLedCount
constexpr float kTriangleEnvelopeFadeSeconds
uint32_t gTriangleFireAtMs
constexpr uint8_t kPreviewLedCount
fl::audio::SoundLevelMeter gSoundLevelMeter
constexpr uint8_t kTriangleLedCount
float gSoundPressureDbSpl
constexpr float kTriangleBassThreshold
constexpr uint8_t kRightTriangleStart
void fireAnalyzer(float bass, float threshold, float minIntensity, float &trigger)
fl::audio::Config audioConfig
uint32_t gLastQualifyingBeatMs
fl::UISlider minimumBeatConfidence("Minimum Vibe Beat Confidence", kDefaultMinimumBeatConfidence, 0.0f, 1.0f, 0.05f)
fl::ScreenMap makePreviewMap()
float applyAttackDecay(float value, float target, float attackSeconds, float decaySeconds, float deltaSeconds)
fl::UITitle title("HydroPack Stage Music Launch")
uint32_t gMusicWarmupStartedMs
float getVibeBeatConfidence(const fl::audio::detector::VibeLevels &levels)
constexpr uint8_t kCenterStart
constexpr float kDefaultStageThresholdDbSpl
constexpr float kMaximumMusicZcf
constexpr uint32_t kMusicWarmupMs
constexpr float kCenterEnvelopeFadeSeconds
constexpr uint32_t kTriangleLaunchDelayMs
const fl::vec2f kHydroPackLedLayout[]
uint32_t gMusicActiveUntilMs
fl::shared_ptr< fl::audio::Processor > gAudio
constexpr uint32_t kMusicHoldMs
fl::UIAudio audioUi("Audio Input", audioConfig)
constexpr float kMusicModeFadeSeconds
float gPendingTriangleLevel
void advanceDoubleEnvelope(float &trigger, float &stage, float &level, float attackSeconds, float decaySeconds, float deltaSeconds)
constexpr float kCenterEnvelopeAttackSeconds
constexpr float kCenterBassThreshold
constexpr float kTriangleEnvelopeAttackSeconds
float advanceLinearFade(float value, float target, float durationSeconds, float deltaSeconds)
constexpr common_type_t< T, U > max(T a, U b) FL_NO_EXCEPT
FL_DISABLE_WARNING_PUSH U constexpr common_type_t< T, U > min(T a, U b) FL_NO_EXCEPT
constexpr enable_if< is_fixed_point< T >::value, T >::type clamp(T x, T lo, T hi) FL_NO_EXCEPT
void printf(const char *format) FL_NO_EXCEPT
#define FL_STATIC_ASSERT(...)
Portable compile-time assertion wrapper.
Aggregator header for the fl/ui/ family of per-element UI types.