48 lines
1.4 KiB
C
48 lines
1.4 KiB
C
|
|
#pragma once
|
||
|
|
|
||
|
|
#include <Arduino.h>
|
||
|
|
#include <arduinoFFT.h>
|
||
|
|
#include <vector>
|
||
|
|
#include <deque>
|
||
|
|
#include "Config.h"
|
||
|
|
|
||
|
|
struct DetectedNote {
|
||
|
|
float frequency;
|
||
|
|
float magnitude;
|
||
|
|
uint8_t noteNumber; // MIDI note number for easy identification
|
||
|
|
uint32_t startTime; // When the note was first detected
|
||
|
|
uint32_t lastSeenTime; // Last time this note was detected
|
||
|
|
};
|
||
|
|
|
||
|
|
class NoteDetector {
|
||
|
|
public:
|
||
|
|
NoteDetector();
|
||
|
|
void analyzeSamples(const int16_t* samples, size_t sampleCount);
|
||
|
|
const std::vector<DetectedNote>& getDetectedNotes() const { return detectedNotes; }
|
||
|
|
const double* getSpectrum() const { return vReal; }
|
||
|
|
void beginCalibration();
|
||
|
|
void endCalibration();
|
||
|
|
bool isCalibrating() const { return calibrationMode; }
|
||
|
|
|
||
|
|
// Threshold adjustment methods
|
||
|
|
void adjustThreshold(float delta);
|
||
|
|
float getCurrentThreshold() const { return dynamicThreshold; }
|
||
|
|
|
||
|
|
private:
|
||
|
|
arduinoFFT FFT;
|
||
|
|
double vReal[Config::FFT_SIZE];
|
||
|
|
double vImag[Config::FFT_SIZE];
|
||
|
|
std::vector<DetectedNote> detectedNotes;
|
||
|
|
std::deque<float> peakMagnitudeHistory; // For calibration
|
||
|
|
|
||
|
|
bool calibrationMode;
|
||
|
|
uint32_t calibrationStartTime;
|
||
|
|
float dynamicThreshold;
|
||
|
|
|
||
|
|
uint8_t freqToNoteNumber(float frequency) const;
|
||
|
|
bool isNoteFrequency(float frequency) const;
|
||
|
|
bool isHarmonic(float freq1, float freq2, float tolerance) const;
|
||
|
|
void findPeaks();
|
||
|
|
void updateNoteTimings();
|
||
|
|
void calculateDynamicThreshold();
|
||
|
|
};
|