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()
|