diff options
Diffstat (limited to 'tuner.cpp')
-rw-r--r-- | tuner.cpp | 40 |
1 files changed, 37 insertions, 3 deletions
@@ -2,12 +2,19 @@ #include "autocorrelation.h" #include "fft.h" +#include "util.h" + +#include <algorithm> +#include <cmath> + +using namespace RIT; struct RIT::Tuner::Impl { public: - Impl(int size, int f_sample): mAC(size), m_f_sample(f_sample) {} + Impl(int size, int f_sample): mAC(size), m_f_sample(f_sample), mSize(size) {} RIT::AutoCorrelation mAC; int m_f_sample; + int mSize; }; RIT::Tuner::Tuner(int size, int f_sample): mImpl(std::make_unique<RIT::Tuner::Impl>(size, f_sample)) @@ -16,9 +23,36 @@ RIT::Tuner::Tuner(int size, int f_sample): mImpl(std::make_unique<RIT::Tuner::Im RIT::Tuner::~Tuner(){} +namespace { + const std::vector<std::string> noteNames{ "A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#" }; + const double base = std::pow(2.0, 1./12); + + RIT::Pitch getPitch(double f) + { + double noteIndexD = std::log(f / 110.0) / std::log(base) + 0.5; + + double noteIndexI{}; + double deviation = std::modf(noteIndexD, ¬eIndexI) - 0.5; + int noteIndex = int(noteIndexI); + + noteIndex %= 12; + + return RIT::Pitch {f, deviation, noteNames[noteIndex]}; + } +} + RIT::Pitch RIT::Tuner::operator() (const std::vector<std::complex<double>> &v) { - std::vector<std::complex<double>> autoCorrelation = mImpl->mAC(v); + std::vector<double> autoCorrelation = magnitudes(mImpl->mAC(v)); + + auto maxElement = std::max_element(std::begin(autoCorrelation) + 1, std::begin(autoCorrelation) + mImpl->mSize / 2); + + int index = maxElement - std::begin(autoCorrelation); + + if (autoCorrelation[index] > autoCorrelation[index - 1] && autoCorrelation[index] > autoCorrelation[index + 1]) { + double f = double(mImpl->m_f_sample) / index; + return getPitch(f); + } - return Pitch(); + return Pitch{}; } |