#include "tuner.h" #include "autocorrelation.h" #include "fft.h" #include "util.h" #include #include #include using namespace RIT; struct RIT::Tuner::Impl { public: 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(size, f_sample)) { } RIT::Tuner::~Tuner(){} namespace { const std::vector 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> &v) { std::vector 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); //std::cout << "DEBUG" << std::endl; if (autoCorrelation[index] > autoCorrelation[index - 1] && autoCorrelation[index] > autoCorrelation[index + 1]) { double f = double(mImpl->m_f_sample) / index; //std::cout << "DEBUG f = " << f << std::endl; return getPitch(f); } return Pitch{}; } double RIT::Tuner::fMin() { return double(mImpl->m_f_sample) / mImpl->mSize; } double RIT::Tuner::fMax() { return double(mImpl->m_f_sample) / 2; }