42 for (
int i = 0; i < 12; i++) {
64 u32 timestamp = context->getTimestamp();
110 for (
int i = 0; i < 12; i++) {
135 for (
int i = 0; i < 12; i++) {
143 for (
int i = 0; i < 12; i++) {
150 const fl::size numBins = linearBins.
size();
151 const float fmin =
fft.linearFmin();
152 const float fmax =
fft.linearFmax();
153 const float linearBinWidth = (numBins > 0) ? (fmax - fmin) /
static_cast<float>(numBins) : 1.0f;
155 for (fl::size binIdx = 0; binIdx < numBins; binIdx++) {
156 float magnitude = linearBins[binIdx];
157 if (magnitude < 1e-6f)
continue;
160 float freq = fmin + (
static_cast<float>(binIdx) + 0.5f) * linearBinWidth;
163 if (freq < 60.0f)
continue;
166 float midiNote = 69.0f + 12.0f * (
fl::logf(freq / 440.0f) /
fl::logf(2.0f));
169 int pitchClass =
static_cast<int>(midiNote + 0.5f) % 12;
170 if (pitchClass < 0) pitchClass += 12;
173 mChroma[pitchClass] += magnitude;
181 float bestScore = 0.0f;
186 for (
int root = 0; root < 12; root++) {
190 if (score > bestScore) {
199 if (bestScore < 0.3f) {
203 return Chord(bestRoot, bestType, bestScore, timestamp);
212 if (!tmpl)
return 0.0f;
215 float matchScore = 0.0f;
216 float totalChroma = 0.0f;
219 for (
int i = 0; i < tmpl->
numNotes; i++) {
221 if (interval < 0)
break;
222 int pitchClass = (root + interval) % 12;
223 matchScore += chroma[pitchClass];
227 for (
int i = 0; i < 12; i++) {
228 totalChroma += chroma[i];
232 float nonChordEnergy = totalChroma - matchScore;
236 if (totalChroma > 1e-6f) {
237 score = matchScore / totalChroma;
238 score -= 0.3f * (nonChordEnergy / totalChroma);
261 for (
int i = 0; i < 12; i++) {
262 if (chroma[i] > maxVal) {
268 if (maxVal > 1e-6f) {
269 for (
int i = 0; i < 12; i++) {
277 for (
int i = 0; i < 12; i++) {
278 float diff = a[i] - b[i];
286 static const char* noteNames[] = {
287 "C",
"C#",
"D",
"D#",
"E",
"F",
"F#",
"G",
"G#",
"A",
"A#",
"B"
function_list< void()> onChordEnd
bool isSimilarChord(const Chord &a, const Chord &b)
flat_map< int, const ChordTemplate * > mTemplateMap
void normalizeChroma(float *chroma)
function_list< void(const Chord &chord)> onChord
float chromaDistance(const float *a, const float *b)
function_list< void(const Chord &chord)> onChordChange
float mConfidenceThreshold
ChordDetector() FL_NOEXCEPT
void calculateChroma(const fft::Bins &fft)
void update(shared_ptr< Context > context) override
void fireCallbacks() override
float matchChordPattern(const float *chroma, int root, ChordType type)
shared_ptr< const fft::Bins > mRetainedFFT
~ChordDetector() FL_NOEXCEPT override
Chord detectChord(const float *chroma, u32 timestamp)
void initializeTemplateMap()
constexpr fl::size size() const FL_NOEXCEPT
Centralized logging categories for FastLED hardware interfaces and subsystems.
static const int kNumChordTemplates
static const ChordTemplate kChordTemplates[]
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
float logf(float value) FL_NOEXCEPT
Base definition for an LED controller.
const char * getTypeName() const
const char * getRootName() const