FastLED 3.10.8
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_NO_EXCEPT : valence(0.0f), arousal(0.0f), confidence(0.0f), timestamp(0), duration(0) {}
33
34 bool isValid() const FL_NO_EXCEPT { 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 FL_NO_EXCEPT {
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) FL_NO_EXCEPT override;
71 void fireCallbacks() FL_NO_EXCEPT override;
72 bool needsFFT() const FL_NO_EXCEPT override { return true; }
73 bool needsFFTHistory() const FL_NO_EXCEPT override { return true; }
74 const char* getName() const FL_NO_EXCEPT override { return "MoodAnalyzer"; }
75 void reset() FL_NO_EXCEPT 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 FL_NO_EXCEPT { return mCurrentMood; }
84 float getValence() const FL_NO_EXCEPT { return mCurrentMood.valence; }
85 float getArousal() const FL_NO_EXCEPT { return mCurrentMood.arousal; }
86 Mood::Category getMoodCategory() const FL_NO_EXCEPT { return mCurrentMood.getCategory(); }
87
88 // Configuration
89 void setConfidenceThreshold(float threshold) FL_NO_EXCEPT { mConfidenceThreshold = threshold; }
91 void setAveragingFrames(int frames) FL_NO_EXCEPT { 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) FL_NO_EXCEPT;
118 float calculateSpectralFlux(const fft::Bins& fft, const fft::Bins* prevFFT) FL_NO_EXCEPT;
119 float calculateValence(float centroid, float rolloff, float flux) FL_NO_EXCEPT;
120 float calculateArousal(float rms, float zcr, float flux) FL_NO_EXCEPT;
121 float calculateConfidence(float valence, float arousal) FL_NO_EXCEPT;
122 bool shouldChangeMood(const Mood& newMood) FL_NO_EXCEPT;
123};
124
125} // namespace detector
126} // namespace audio
127} // namespace fl
float rms(fl::span< const int16_t > data)
Definition simple.h:104
float calculateSpectralRolloff(const fft::Bins &fft, float threshold=0.85f) FL_NO_EXCEPT
float calculateConfidence(float valence, float arousal) FL_NO_EXCEPT
fl::vector< float > mArousalHistory
void fireCallbacks() FL_NO_EXCEPT override
~MoodAnalyzer() FL_NO_EXCEPT override
float getValence() const FL_NO_EXCEPT
function_list< void(float valence, float arousal)> onValenceArousal
bool needsFFT() const FL_NO_EXCEPT override
float calculateArousal(float rms, float zcr, float flux) FL_NO_EXCEPT
float getArousal() const FL_NO_EXCEPT
Mood::Category getMoodCategory() const FL_NO_EXCEPT
function_list< void(const Mood &mood)> onMoodChange
float calculateValence(float centroid, float rolloff, float flux) FL_NO_EXCEPT
fl::vector< float > mValenceHistory
void reset() FL_NO_EXCEPT override
shared_ptr< const fft::Bins > mRetainedFFT
bool needsFFTHistory() const FL_NO_EXCEPT override
void setConfidenceThreshold(float threshold) FL_NO_EXCEPT
void setAveragingFrames(int frames) FL_NO_EXCEPT
const Mood & getCurrentMood() const FL_NO_EXCEPT
function_list< void(const Mood &mood)> onMood
void update(shared_ptr< Context > context) FL_NO_EXCEPT override
float calculateSpectralFlux(const fft::Bins &fft, const fft::Bins *prevFFT) FL_NO_EXCEPT
float calculateSpectralCentroid(const fft::Bins &fft) FL_NO_EXCEPT
void setMinDuration(u32 ms) FL_NO_EXCEPT
const char * getName() const FL_NO_EXCEPT override
bool shouldChangeMood(const Mood &newMood) FL_NO_EXCEPT
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
constexpr enable_if< is_fixed_point< T >::value, T >::type abs(T x) FL_NO_EXCEPT
Base definition for an LED controller.
Definition crgb.hpp:179
const char * getCategoryName() const FL_NO_EXCEPT
bool isValid() const FL_NO_EXCEPT
Category getCategory() const FL_NO_EXCEPT