42 for (
int i = 0; i < 12; i++) {
64 u32 timestamp = context->getTimestamp();
108 for (
int i = 0; i < 12; i++) {
133 for (
int i = 0; i < 12; i++) {
141 for (
int i = 0; i < 12; i++) {
148 const fl::size numBins = linearBins.
size();
149 const float fmin =
fft.linearFmin();
150 const float fmax =
fft.linearFmax();
151 const float linearBinWidth = (numBins > 0) ? (fmax - fmin) /
static_cast<float>(numBins) : 1.0f;
153 for (fl::size binIdx = 0; binIdx < numBins; binIdx++) {
154 float magnitude = linearBins[binIdx];
155 if (magnitude < 1e-6f)
continue;
158 float freq = fmin + (
static_cast<float>(binIdx) + 0.5f) * linearBinWidth;
161 if (freq < 60.0f)
continue;
164 float midiNote = 69.0f + 12.0f * (
fl::logf(freq / 440.0f) /
fl::logf(2.0f));
167 int pitchClass =
static_cast<int>(midiNote + 0.5f) % 12;
168 if (pitchClass < 0) pitchClass += 12;
171 mChroma[pitchClass] += magnitude;
179 float bestScore = 0.0f;
184 for (
int root = 0; root < 12; root++) {
188 if (score > bestScore) {
197 if (bestScore < 0.3f) {
201 return Chord(bestRoot, bestType, bestScore, timestamp);
210 if (!tmpl)
return 0.0f;
213 float matchScore = 0.0f;
214 float totalChroma = 0.0f;
217 for (
int i = 0; i < tmpl->
numNotes; i++) {
219 if (interval < 0)
break;
220 int pitchClass = (root + interval) % 12;
221 matchScore += chroma[pitchClass];
225 for (
int i = 0; i < 12; i++) {
226 totalChroma += chroma[i];
230 float nonChordEnergy = totalChroma - matchScore;
234 if (totalChroma > 1e-6f) {
235 score = matchScore / totalChroma;
236 score -= 0.3f * (nonChordEnergy / totalChroma);
244 if (!a.isValid() || !b.isValid())
return false;
247 if (a.rootNote == b.rootNote && a.type == b.type) {
259 for (
int i = 0; i < 12; i++) {
260 if (chroma[i] > maxVal) {
266 if (maxVal > 1e-6f) {
267 for (
int i = 0; i < 12; i++) {
275 for (
int i = 0; i < 12; i++) {
276 float diff = a[i] - b[i];
284 static const char* noteNames[] = {
285 "C",
"C#",
"D",
"D#",
"E",
"F",
"F#",
"G",
"G#",
"A",
"A#",
"B"
function_list< void()> onChordEnd
bool isSimilarChord(const Chord &a, const Chord &b) FL_NO_EXCEPT
float matchChordPattern(const float *chroma, int root, ChordType type) FL_NO_EXCEPT
flat_map< int, const ChordTemplate * > mTemplateMap
function_list< void(const Chord &chord)> onChord
Chord detectChord(const float *chroma, u32 timestamp) FL_NO_EXCEPT
function_list< void(const Chord &chord)> onChordChange
float chromaDistance(const float *a, const float *b) FL_NO_EXCEPT
float mConfidenceThreshold
void update(shared_ptr< Context > context) FL_NO_EXCEPT override
void calculateChroma(const fft::Bins &fft) FL_NO_EXCEPT
void normalizeChroma(float *chroma) FL_NO_EXCEPT
~ChordDetector() FL_NO_EXCEPT override
ChordDetector() FL_NO_EXCEPT
shared_ptr< const fft::Bins > mRetainedFFT
void reset() FL_NO_EXCEPT override
void initializeTemplateMap() FL_NO_EXCEPT
void fireCallbacks() FL_NO_EXCEPT override
constexpr fl::size size() const FL_NO_EXCEPT
Centralized logging categories for FastLED hardware interfaces and subsystems.
static const int kNumChordTemplates
static const ChordTemplate kChordTemplates[]
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
constexpr enable_if< is_fixed_point< T >::value, T >::type sqrt(T x) FL_NO_EXCEPT
Base definition for an LED controller.
bool isValid() const FL_NO_EXCEPT
const char * getTypeName() const FL_NO_EXCEPT
const char * getRootName() const FL_NO_EXCEPT