FastLED 3.9.15
Loading...
Searching...
No Matches
mood_analyzer.h
Go to the documentation of this file.
1// MoodAnalyzer - Mood and emotion detection from audio features
2// Part of FastLED Audio Processing System (Phase 3 - Tier 3)
3
4#pragma once
5
7#include "fl/stl/function.h"
8#include "fl/stl/int.h"
9#include "fl/stl/noexcept.h"
10
11namespace fl {
12namespace audio {
13namespace detector {
14
15// Mood state representing emotional characteristics
16struct Mood {
17 float valence; // Positivity/negativity (-1.0 to 1.0, negative=sad, positive=happy)
18 float arousal; // Energy/calmness (0.0 to 1.0, low=calm, high=energetic)
19 float confidence; // Detection confidence (0.0 to 1.0)
20 u32 timestamp; // Timestamp of mood detection
21 u32 duration; // Duration mood has been stable (ms)
22
23 // Mood categories (derived from valence/arousal)
24 enum Category {
25 CALM_NEGATIVE, // Low arousal, negative valence (sad, melancholic)
26 CALM_POSITIVE, // Low arousal, positive valence (peaceful, content)
27 ENERGETIC_NEGATIVE, // High arousal, negative valence (angry, tense)
28 ENERGETIC_POSITIVE, // High arousal, positive valence (happy, excited)
29 NEUTRAL // Near center, no strong mood
30 };
31
32 Mood() FL_NOEXCEPT : valence(0.0f), arousal(0.0f), confidence(0.0f), timestamp(0), duration(0) {}
33
34 bool isValid() const { return confidence > 0.0f; }
35
37 const float NEUTRAL_THRESHOLD = 0.3f;
38
39 // Near center = neutral
40 if (abs(valence) < NEUTRAL_THRESHOLD && arousal < NEUTRAL_THRESHOLD + 0.2f) {
41 return NEUTRAL;
42 }
43
44 // Quadrant-based categorization
45 if (arousal < 0.5f) {
46 return valence < 0.0f ? CALM_NEGATIVE : CALM_POSITIVE;
47 } else {
49 }
50 }
51
52 const char* getCategoryName() const {
53 switch (getCategory()) {
54 case CALM_NEGATIVE: return "calm_negative";
55 case CALM_POSITIVE: return "calm_positive";
56 case ENERGETIC_NEGATIVE: return "energetic_negative";
57 case ENERGETIC_POSITIVE: return "energetic_positive";
58 case NEUTRAL: return "neutral";
59 default: return "unknown";
60 }
61 }
62};
63
64class MoodAnalyzer : public Detector {
65public:
68
69 // Detector interface
70 void update(shared_ptr<Context> context) override;
71 void fireCallbacks() override;
72 bool needsFFT() const override { return true; }
73 bool needsFFTHistory() const override { return true; }
74 const char* getName() const override { return "MoodAnalyzer"; }
75 void reset() override;
76
77 // Event callbacks (multiple listeners supported)
78 function_list<void(const Mood& mood)> onMood; // Every frame
79 function_list<void(const Mood& mood)> onMoodChange; // Mood category changes
80 function_list<void(float valence, float arousal)> onValenceArousal; // Raw values
81
82 // State access
83 const Mood& getCurrentMood() const { return mCurrentMood; }
84 float getValence() const { return mCurrentMood.valence; }
85 float getArousal() const { return mCurrentMood.arousal; }
86 Mood::Category getMoodCategory() const { return mCurrentMood.getCategory(); }
87
88 // Configuration
89 void setConfidenceThreshold(float threshold) { mConfidenceThreshold = threshold; }
90 void setMinDuration(u32 ms) { mMinDuration = ms; }
91 void setAveragingFrames(int frames) { mAveragingFrames = frames; }
92
93private:
96 bool mMoodChanged = false;
100
101 // Audio features for mood analysis
107
108 // Feature history for temporal averaging
112
114
115 // Analysis methods
117 float calculateSpectralRolloff(const fft::Bins& fft, float threshold = 0.85f);
118 float calculateSpectralFlux(const fft::Bins& fft, const fft::Bins* prevFFT);
119 float calculateValence(float centroid, float rolloff, float flux);
120 float calculateArousal(float rms, float zcr, float flux);
121 float calculateConfidence(float valence, float arousal);
122 bool shouldChangeMood(const Mood& newMood);
123};
124
125} // namespace detector
126} // namespace audio
127} // namespace fl
float rms(fl::span< const int16_t > data)
Definition simple.h:104
const Mood & getCurrentMood() const
float calculateSpectralCentroid(const fft::Bins &fft)
Mood::Category getMoodCategory() const
fl::vector< float > mArousalHistory
function_list< void(float valence, float arousal)> onValenceArousal
void update(shared_ptr< Context > context) override
function_list< void(const Mood &mood)> onMoodChange
bool needsFFTHistory() const override
bool shouldChangeMood(const Mood &newMood)
fl::vector< float > mValenceHistory
shared_ptr< const fft::Bins > mRetainedFFT
float calculateSpectralFlux(const fft::Bins &fft, const fft::Bins *prevFFT)
float calculateSpectralRolloff(const fft::Bins &fft, float threshold=0.85f)
float calculateArousal(float rms, float zcr, float flux)
bool needsFFT() const override
float calculateValence(float centroid, float rolloff, float flux)
~MoodAnalyzer() FL_NOEXCEPT override
function_list< void(const Mood &mood)> onMood
const char * getName() const override
void setConfidenceThreshold(float threshold)
float calculateConfidence(float valence, float arousal)
constexpr enable_if< is_fixed_point< T >::value, T >::type abs(T x) FL_NOEXCEPT
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_NOEXCEPT
Category getCategory() const
const char * getCategoryName() const