53 "C",
"C#",
"D",
"D#",
"E",
"F",
"F#",
"G",
"G#",
"A",
"A#",
"B"
66 if (bufferSize < 8)
return;
69 fl::snprintf(buffer, bufferSize,
"%s %s", root, quality);
88 for (
int i = 0; i < 12; i++) {
100 float majorSum = 0.0f, majorSqSum = 0.0f;
101 for (
int i = 0; i < 12; i++) {
109 float minorSum = 0.0f, minorSqSum = 0.0f;
110 for (
int i = 0; i < 12; i++) {
122 u32 timestamp = context->getTimestamp();
125 float chroma[12] = {0};
133 float avgChroma[12] = {0};
149 bool acceptChange =
false;
198 for (
int i = 0; i < 12; i++) {
209 for (
int i = 0; i < 12; i++) {
216 const int numBins =
static_cast<int>(linearBins.
size());
217 const float fmin =
fft.linearFmin();
218 const float fmax =
fft.linearFmax();
219 const float linearBinWidth = (numBins > 0) ? (fmax - fmin) /
static_cast<float>(numBins) : 1.0f;
222 for (
int bin = 0; bin < numBins; bin++) {
223 float magnitude = linearBins[bin];
224 if (magnitude < 1e-6f)
continue;
227 float freq = fmin + (
static_cast<float>(bin) + 0.5f) * linearBinWidth;
230 if (freq < 60.0f)
continue;
234 float midiNote = 69.0f + 12.0f * (
fl::logf(freq / 440.0f) /
fl::logf(2.0f));
237 int pitchClass =
static_cast<int>(midiNote + 0.5f) % 12;
238 if (pitchClass < 0) pitchClass += 12;
241 chroma[pitchClass] += magnitude;
248 for (
int i = 0; i < 12; i++) {
249 if (chroma[i] > maxVal) {
255 if (maxVal > 1e-6f) {
256 for (
int i = 0; i < 12; i++) {
264 for (
int i = 0; i < 12; i++) {
281 for (
int i = 0; i < 12; i++) {
288 for (
int i = 0; i < 12; i++) {
302 float bestCorrelation = -1.0f;
304 bool bestIsMinor =
false;
307 for (
int root = 0; root < 12; root++) {
310 if (majorCorr > bestCorrelation) {
311 bestCorrelation = majorCorr;
318 if (minorCorr > bestCorrelation) {
319 bestCorrelation = minorCorr;
327 float confidence = (bestCorrelation + 1.0f) / 2.0f;
330 return Key(bestRoot, bestIsMinor, confidence, timestamp);
338 float profileMean, profileStdDev;
346 if (profileStdDev < 1e-6f) profileStdDev = 1.0f;
349 float chromaSum = 0.0f;
350 float chromaSqSum = 0.0f;
351 for (
int i = 0; i < 12; i++) {
352 chromaSum += chroma[i];
353 chromaSqSum += chroma[i] * chroma[i];
355 float chromaMean = chromaSum / 12.0f;
356 float chromaStdDev =
sqrtf((chromaSqSum / 12.0f) - (chromaMean * chromaMean));
357 if (chromaStdDev < 1e-6f) chromaStdDev = 1.0f;
360 float correlation = 0.0f;
361 for (
int i = 0; i < 12; i++) {
362 int profileIdx = (i - rootNote + 12) % 12;
363 float chromaNorm = (chroma[i] - chromaMean) / chromaStdDev;
364 float profileNorm = (profile[profileIdx] - profileMean) / profileStdDev;
365 correlation += chromaNorm * profileNorm;
367 correlation /= 12.0f;
shared_ptr< const fft::Bins > mRetainedFFT
void reset() FL_NO_EXCEPT override
void updateChromaHistory(const float *chroma) FL_NO_EXCEPT
~KeyDetector() FL_NO_EXCEPT override
static const float MAJOR_PROFILE[12]
vector< float > mChromaHistory[12]
void normalizeChroma(float *chroma) FL_NO_EXCEPT
void fireCallbacks() FL_NO_EXCEPT override
void extractChroma(const fft::Bins &fft, float *chroma) FL_NO_EXCEPT
void getAveragedChroma(float *chroma) FL_NO_EXCEPT
function_list< void()> onKeyEnd
Key detectKey(const float *chroma, u32 timestamp) FL_NO_EXCEPT
float mMinorProfileStdDev
function_list< void(const Key &key)> onKeyChange
KeyDetector() FL_NO_EXCEPT
float mMajorProfileStdDev
static const float MINOR_PROFILE[12]
void initializeProfileStats() FL_NO_EXCEPT
float correlateWithProfile(const float *chroma, const float *profile, int rootNote) FL_NO_EXCEPT
function_list< void(const Key &key)> onKey
float mConfidenceThreshold
void update(shared_ptr< Context > context) FL_NO_EXCEPT override
constexpr fl::size size() const FL_NO_EXCEPT
Centralized logging categories for FastLED hardware interfaces and subsystems.
static const char * NOTE_NAMES[12]
float logf(float value) FL_NO_EXCEPT
constexpr common_type_t< T, U > max(T a, U b) FL_NO_EXCEPT
u8 u8 fract8 blur_amount FL_NO_EXCEPT
int snprintf(char *buffer, fl::size size, const char *format) FL_NO_EXCEPT
FL_DISABLE_WARNING_PUSH U constexpr common_type_t< T, U > min(T a, U b) FL_NO_EXCEPT
float sqrtf(float value) FL_NO_EXCEPT
Base definition for an LED controller.
const char * getRootName() const FL_NO_EXCEPT
void getKeyName(char *buffer, size_t bufferSize) const FL_NO_EXCEPT
const char * getQuality() const FL_NO_EXCEPT