summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile7
-rw-r--r--TODO1
-rw-r--r--fft.cpp27
-rw-r--r--fft.h4
-rw-r--r--testsuite.cpp3
-rw-r--r--tuner.cpp40
-rw-r--r--tunerdemo.cpp5
-rw-r--r--util.cpp25
-rw-r--r--util.h15
9 files changed, 92 insertions, 35 deletions
diff --git a/Makefile b/Makefile
index c78f4d7..c6cd4e3 100644
--- a/Makefile
+++ b/Makefile
@@ -12,10 +12,10 @@ PREFIX=/usr/local/bin
all: tunerdemo testsuite
-tunerdemo: fft.o autocorrelation.o tuner.o tunerdemo.o
+tunerdemo: util.o fft.o autocorrelation.o tuner.o tunerdemo.o
$(CXX) $(CXXFLAGS) -o $@ $^
-testsuite: fft.o autocorrelation.o tuner.o testsuite.o
+testsuite: util.o fft.o autocorrelation.o tuner.o testsuite.o
$(CXX) $(CXXFLAGS) -o $@ $^
fft.o: fft.cpp fft.h
@@ -27,6 +27,9 @@ autocorrelation.o: autocorrelation.cpp autocorrelation.h
tuner.o: tuner.cpp tuner.h
$(CXX) $(CXXFLAGS) -c -o $@ $<
+util.o: util.cpp util.h
+ $(CXX) $(CXXFLAGS) -c -o $@ $<
+
testsuite.o: testsuite.cpp fft.h autocorrelation.h tuner.h
$(CXX) $(CXXFLAGS) -c -o $@ $<
diff --git a/TODO b/TODO
index e31bca0..dff5398 100644
--- a/TODO
+++ b/TODO
@@ -2,6 +2,7 @@ TODO
====
google test
+test: compare w/ naive implementation autocorrelation, ifft
debian
tuner
diff --git a/fft.cpp b/fft.cpp
index a8009ad..12aeece 100644
--- a/fft.cpp
+++ b/fft.cpp
@@ -2,6 +2,8 @@
#include "fft.h"
+#include "util.h"
+
#include <algorithm>
#include <chrono>
#include <cmath>
@@ -15,15 +17,6 @@
namespace { // Helper functions
- bool is_power_of_two(unsigned int n) {
- return n != 0 && (n & (n - 1)) == 0;
- }
-}
-
-std::vector<double> RIT::magnitudes(std::vector<std::complex<double>>& v) {
- std::vector<double> result(v.size());
- std::transform(std::begin(v), std::end(v), std::begin(result), std::abs<double>);
- return result;
}
RIT::FFT::FFT(int size, bool halfOnly): mSize(size), order(size), expLUT(size/2), mFlagHalfOnly(halfOnly) {
@@ -33,7 +26,7 @@ RIT::FFT::FFT(int size, bool halfOnly): mSize(size), order(size), expLUT(size/2)
// reorder LUT
for (int i = 0; i < size; ++i) {
- order[i] = bitreverse(i);
+ order[i] = RIT::bitreverse(i, size);
}
// exp LUT
@@ -63,20 +56,6 @@ RIT::FFT& RIT::FFT::SetHalfOnly(bool enable) {
return *this;
}
-int RIT::FFT::bitreverse(int i) const {
- int size{mSize};
- int result{0};
-
- while (size > 1) {
- result <<= 1;
- result |= i & 1;
- i >>= 1;
- size >>= 1;
- }
-
- return result;
-}
-
void RIT::FFT::reorder(const std::vector<std::complex<double>>& src, std::vector<std::complex<double>>& dst) const {
int size = src.size();
diff --git a/fft.h b/fft.h
index 980b4b3..4bc493d 100644
--- a/fft.h
+++ b/fft.h
@@ -24,8 +24,6 @@ public:
FFT& SetHalfOnly(bool enable);
private:
- int bitreverse(int i) const;
-
void reorder(const std::vector<std::complex<double>>& src, std::vector<std::complex<double>>& dst) const;
void fft_recursive(std::vector<std::complex<double>>::iterator X, int N) const;
void fft_half(std::vector<std::complex<double>>::iterator X, int N) const;
@@ -44,6 +42,4 @@ private:
std::unique_ptr<Impl> mImpl;
}; // class IFFT
-std::vector<double> magnitudes(std::vector<std::complex<double>>& v);
-
} // namespace RIT
diff --git a/testsuite.cpp b/testsuite.cpp
index 2b8042b..f925b7e 100644
--- a/testsuite.cpp
+++ b/testsuite.cpp
@@ -1,8 +1,9 @@
// FFT Test
-#include "fft.h"
#include "autocorrelation.h"
+#include "fft.h"
#include "tuner.h"
+#include "util.h"
#include <complex>
#include <chrono>
diff --git a/tuner.cpp b/tuner.cpp
index d1833a3..3013390 100644
--- a/tuner.cpp
+++ b/tuner.cpp
@@ -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, &noteIndexI) - 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{};
}
diff --git a/tunerdemo.cpp b/tunerdemo.cpp
index 716bd8e..e70afb2 100644
--- a/tunerdemo.cpp
+++ b/tunerdemo.cpp
@@ -23,7 +23,10 @@ int main(int argc, char* argv[]) {
auto start = std::chrono::high_resolution_clock::now();
RIT::Pitch pitch = tuner(dataIn);
auto end = std::chrono::high_resolution_clock::now();
- std::cout << "Detected Note: " << pitch.name
+ std::string name = pitch.name;
+ if (name == "")
+ name = "<none>";
+ std::cout << "Detected Note: " << name
<< " Deviation: " << pitch.deviation
<< " Frequency: " << pitch.f
<< ", took " << std::chrono::nanoseconds(end - start).count() * 0.000001 << "ms"
diff --git a/util.cpp b/util.cpp
new file mode 100644
index 0000000..2a81823
--- /dev/null
+++ b/util.cpp
@@ -0,0 +1,25 @@
+#include "util.h"
+
+bool RIT::is_power_of_two(unsigned int n) {
+ return n != 0 && (n & (n - 1)) == 0;
+}
+
+std::vector<double> RIT::magnitudes(const std::vector<std::complex<double>>& v) {
+ std::vector<double> result(v.size());
+ std::transform(std::begin(v), std::end(v), std::begin(result), std::abs<double>);
+ return result;
+}
+
+/// size: fft size in sample points, power of 2
+int RIT::bitreverse(int i, int size) {
+ int result{0};
+
+ while (size > 1) {
+ result <<= 1;
+ result |= i & 1;
+ i >>= 1;
+ size >>= 1;
+ }
+
+ return result;
+}
diff --git a/util.h b/util.h
new file mode 100644
index 0000000..1d64a80
--- /dev/null
+++ b/util.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <complex>
+#include <vector>
+
+namespace RIT {
+
+int bitreverse(int i, int size);
+
+bool is_power_of_two(unsigned int n);
+
+std::vector<double> magnitudes(const std::vector<std::complex<double>>& v);
+
+} // namespace RIT
+