| 178 | } |
| 179 | |
| 180 | Chord ChordDetector::detectChord(const float* chroma, u32 timestamp) { |
| 181 | float bestScore = 0.0f; |
| 182 | int bestRoot = -1; |
| 183 | ChordType bestType = ChordType::UNKNOWN; |
| 184 | |
| 185 | // Try all root notes (0-11) |
| 186 | for (int root = 0; root < 12; root++) { |
| 187 | // Try all chord templates |
| 188 | for (int t = 0; t < kNumChordTemplates; t++) { |
| 189 | float score = matchChordPattern(chroma, root, kChordTemplates[t].type); |
| 190 | if (score > bestScore) { |
| 191 | bestScore = score; |
| 192 | bestRoot = root; |
| 193 | bestType = kChordTemplates[t].type; |
| 194 | } |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | // Confidence threshold |
| 199 | if (bestScore < 0.3f) { |
| 200 | return Chord(); // No valid chord |
| 201 | } |
| 202 | |
| 203 | return Chord(bestRoot, bestType, bestScore, timestamp); |
| 204 | } |
| 205 | |
| 206 | float ChordDetector::matchChordPattern(const float* chroma, int root, ChordType type) { |
| 207 | // Find the matching template using pre-computed lookup (O(1) vs O(n) linear search) |