33 const fft::Bins* prevFFT = context->getHistoricalFFT(1);
58 float avgValence = 0.0f;
59 float avgArousal = 0.0f;
114 float weightedSum = 0.0f;
115 float magnitudeSum = 0.0f;
117 for (
size_t i = 0; i <
fft.raw().size(); i++) {
118 float magnitude =
fft.raw()[i];
119 weightedSum += i * magnitude;
120 magnitudeSum += magnitude;
123 return (magnitudeSum < 1e-6f) ? 0.0f : weightedSum / magnitudeSum;
127 float totalEnergy = 0.0f;
129 for (
size_t i = 0; i <
fft.raw().size(); i++) {
130 float magnitude =
fft.raw()[i];
131 totalEnergy += magnitude * magnitude;
134 float energyThreshold = totalEnergy * threshold;
135 float cumulativeEnergy = 0.0f;
137 for (
size_t i = 0; i <
fft.raw().size(); i++) {
138 float magnitude =
fft.raw()[i];
139 cumulativeEnergy += magnitude * magnitude;
140 if (cumulativeEnergy >= energyThreshold) {
141 return static_cast<float>(i) /
fft.raw().size();
149 if (!prevFFT || prevFFT->
raw().size() !=
fft.raw().size()) {
154 for (
size_t i = 0; i <
fft.raw().size(); i++) {
155 float diff =
fft.raw()[i] - prevFFT->
raw()[i];
168 float normalizedCentroid = centroid / 32.0f;
171 float brightness = normalizedCentroid * rolloff;
174 float stability = 1.0f -
fl::min(1.0f, flux / 10.0f);
177 float valence = (
brightness * 0.6f + stability * 0.4f) * 2.0f - 1.0f;
192 float normalizedZCR =
fl::min(1.0f, zcr);
195 float normalizedFlux =
fl::min(1.0f, flux / 10.0f);
198 float arousal = normalizedRMS * 0.5f + normalizedZCR * 0.2f + normalizedFlux * 0.3f;
208 float distanceFromNeutral =
fl::sqrt(valence * valence + arousal * arousal);
213 float normalizedDistance = distanceFromNeutral / 1.118f;
234 if (confidenceRatio < 1.3f) {
fl::UISlider brightness("Brightness", BRIGHTNESS, 0, 255)
float rms(fl::span< const int16_t > data)
float calculateSpectralCentroid(const fft::Bins &fft)
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
void fireCallbacks() 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)
float calculateValence(float centroid, float rolloff, float flux)
float mConfidenceThreshold
~MoodAnalyzer() FL_NOEXCEPT override
function_list< void(const Mood &mood)> onMood
float calculateConfidence(float valence, float arousal)
MoodAnalyzer() FL_NOEXCEPT
fl::span< const float > raw() const FL_NOEXCEPT
FL_DISABLE_WARNING_PUSH U constexpr common_type_t< T, U > min(T a, U b) FL_NOEXCEPT
constexpr common_type_t< T, U > max(T a, U b) FL_NOEXCEPT
constexpr enable_if< is_fixed_point< T >::value, T >::type sqrt(T x) FL_NOEXCEPT
Base definition for an LED controller.
Category getCategory() const