annotate tests/TestChromagram.cpp @ 222:0990c1cb4049 chroma-key-tuning-review

(Incomplete) unit tests for chroma and key estimation
author Chris Cannam
date Thu, 23 May 2019 13:29:02 +0100
parents
children 1b89d1916cd5
rev   line source
Chris@222 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@222 2
Chris@222 3 #include "dsp/chromagram/Chromagram.h"
Chris@222 4
Chris@222 5 #include <iostream>
Chris@222 6
Chris@222 7 #include <cmath>
Chris@222 8
Chris@222 9 #define BOOST_TEST_DYN_LINK
Chris@222 10 #define BOOST_TEST_MAIN
Chris@222 11
Chris@222 12 #include <boost/test/unit_test.hpp>
Chris@222 13
Chris@222 14 BOOST_AUTO_TEST_SUITE(TestChromagram)
Chris@222 15
Chris@222 16 using std::cout;
Chris@222 17 using std::endl;
Chris@222 18 using std::string;
Chris@222 19 using std::vector;
Chris@222 20
Chris@222 21 string midiPitchName(int midiPitch)
Chris@222 22 {
Chris@222 23 static string names[] = {
Chris@222 24 "C", "C#", "D", "D#",
Chris@222 25 "E", "F", "F#", "G",
Chris@222 26 "G#", "A", "A#", "B"
Chris@222 27 };
Chris@222 28
Chris@222 29 return names[midiPitch % 12];
Chris@222 30 }
Chris@222 31
Chris@222 32 vector<double> generateSinusoid(double frequency,
Chris@222 33 int sampleRate,
Chris@222 34 int length)
Chris@222 35 {
Chris@222 36 vector<double> buffer;
Chris@222 37 buffer.reserve(length);
Chris@222 38 for (int i = 0; i < length; ++i) {
Chris@222 39 buffer.push_back(sin(i * M_PI * 2.0 * frequency / sampleRate));
Chris@222 40 }
Chris@222 41 return buffer;
Chris@222 42 }
Chris@222 43
Chris@222 44 double frequencyForPitch(int midiPitch, double concertA)
Chris@222 45 {
Chris@222 46 return concertA * pow(2.0, (midiPitch - 69.0) / 12.0);
Chris@222 47 }
Chris@222 48
Chris@222 49 BOOST_AUTO_TEST_CASE(sinusoid_12tET)
Chris@222 50 {
Chris@222 51 double concertA = 440.0;
Chris@222 52 int sampleRate = 44100;
Chris@222 53 int bpo = 60;
Chris@222 54
Chris@222 55 ChromaConfig config {
Chris@222 56 sampleRate,
Chris@222 57 frequencyForPitch(36, concertA),
Chris@222 58 frequencyForPitch(108, concertA),
Chris@222 59 bpo,
Chris@222 60 0.0054,
Chris@222 61 MathUtilities::NormaliseNone
Chris@222 62 };
Chris@222 63
Chris@222 64 Chromagram chroma(config);
Chris@222 65
Chris@222 66 for (int midiPitch = 48; midiPitch < 96; ++midiPitch) {
Chris@222 67
Chris@222 68 cout << endl;
Chris@222 69
Chris@222 70 int blockSize = chroma.getFrameSize();
Chris@222 71 int hopSize = chroma.getHopSize();
Chris@222 72 cerr << "blockSize = " << blockSize
Chris@222 73 << ", hopSize = " << hopSize << endl;
Chris@222 74
Chris@222 75 double frequency = frequencyForPitch(midiPitch, concertA);
Chris@222 76 int expectedPeakBin = ((midiPitch - 36) * 5) % bpo;
Chris@222 77
Chris@222 78 cout << "midiPitch = " << midiPitch
Chris@222 79 << ", name = " << midiPitchName(midiPitch)
Chris@222 80 << ", frequency = " << frequency
Chris@222 81 << ", expected peak bin = "
Chris@222 82 << expectedPeakBin << endl;
Chris@222 83
Chris@222 84 vector<double> signal = generateSinusoid(frequency,
Chris@222 85 sampleRate,
Chris@222 86 blockSize);
Chris@222 87
Chris@222 88 double *output = chroma.process(signal.data());
Chris@222 89
Chris@222 90 int peakBin = -1;
Chris@222 91 double peakValue = 0.0;
Chris@222 92
Chris@222 93 for (int i = 0; i < bpo; ++i) {
Chris@222 94 if (i == 0 || output[i] > peakValue) {
Chris@222 95 peakValue = output[i];
Chris@222 96 peakBin = i;
Chris@222 97 }
Chris@222 98 }
Chris@222 99
Chris@222 100 cout << "peak value = " << peakValue << " at bin " << peakBin << endl;
Chris@222 101 cout << "(neighbouring values are "
Chris@222 102 << (peakBin > 0 ? output[peakBin-1] : output[bpo-1])
Chris@222 103 << " and "
Chris@222 104 << (peakBin+1 < bpo ? output[peakBin+1] : output[0])
Chris@222 105 << ")" << endl;
Chris@222 106
Chris@222 107 BOOST_CHECK_EQUAL(peakBin, expectedPeakBin);
Chris@222 108 }
Chris@222 109 }
Chris@222 110
Chris@222 111 BOOST_AUTO_TEST_SUITE_END()