annotate tests/TestChromagram.cpp @ 451:3f913390bcf2

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