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