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/keydetection/GetKeyMode.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(TestGetKeyMode)
|
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 keyName(int index, bool minor)
|
c@451
|
22 {
|
c@451
|
23 static string namesMajor[] = {
|
c@451
|
24 "C", "Db", "D", "Eb",
|
c@451
|
25 "E", "F", "F# / Gb", "G",
|
c@451
|
26 "Ab", "A", "Bb", "B"
|
c@451
|
27 };
|
c@451
|
28
|
c@451
|
29 static string namesMinor[] = {
|
c@451
|
30 "C", "C#", "D", "Eb / D#",
|
c@451
|
31 "E", "F", "F#", "G",
|
c@451
|
32 "G#", "A", "Bb", "B"
|
c@451
|
33 };
|
c@451
|
34
|
c@451
|
35 if (index < 1 || index > 12) return "";
|
c@451
|
36
|
c@451
|
37 std::string name;
|
c@451
|
38 if (minor) name = namesMinor[index - 1] + " minor";
|
c@451
|
39 else name = namesMajor[index - 1] + " major";
|
c@451
|
40 return name;
|
c@451
|
41 }
|
c@451
|
42
|
c@451
|
43 string midiPitchName(int midiPitch)
|
c@451
|
44 {
|
c@451
|
45 static string names[] = {
|
c@451
|
46 "C", "C#", "D", "D#",
|
c@451
|
47 "E", "F", "F#", "G",
|
c@451
|
48 "G#", "A", "A#", "B"
|
c@451
|
49 };
|
c@451
|
50
|
c@451
|
51 return names[midiPitch % 12];
|
c@451
|
52 }
|
c@451
|
53
|
c@451
|
54 vector<double> generateSinusoid(double frequency,
|
c@451
|
55 int sampleRate,
|
c@451
|
56 int length)
|
c@451
|
57 {
|
c@451
|
58 vector<double> buffer;
|
c@451
|
59 buffer.reserve(length);
|
c@451
|
60 for (int i = 0; i < length; ++i) {
|
c@451
|
61 buffer.push_back(sin(i * M_PI * 2.0 * frequency / sampleRate));
|
c@451
|
62 }
|
c@451
|
63 return buffer;
|
c@451
|
64 }
|
c@451
|
65
|
c@451
|
66 BOOST_AUTO_TEST_CASE(sinusoid_12tET)
|
c@451
|
67 {
|
c@451
|
68 double concertA = 440.0;
|
c@451
|
69 int sampleRate = 44100;
|
c@451
|
70
|
c@451
|
71 for (int midiPitch = 48; midiPitch < 96; ++midiPitch) {
|
c@451
|
72
|
cannam@510
|
73 GetKeyMode::Config config(sampleRate, concertA);
|
cannam@510
|
74 GetKeyMode gkm(config);
|
c@451
|
75 int blockSize = gkm.getBlockSize();
|
c@451
|
76 int hopSize = gkm.getHopSize();
|
c@451
|
77
|
c@451
|
78 double frequency = concertA * pow(2.0, (midiPitch - 69.0) / 12.0);
|
cannam@510
|
79
|
c@451
|
80 int blocks = 4;
|
c@451
|
81 int totalLength = blockSize * blocks;
|
c@451
|
82 vector<double> signal = generateSinusoid(frequency, sampleRate,
|
c@451
|
83 totalLength);
|
c@451
|
84
|
c@451
|
85 int key;
|
c@451
|
86
|
c@451
|
87 for (int offset = 0; offset + blockSize < totalLength;
|
c@451
|
88 offset += hopSize) {
|
c@451
|
89 int k = gkm.process(signal.data() + offset);
|
c@451
|
90 if (offset == 0) {
|
c@451
|
91 key = k;
|
c@451
|
92 } else {
|
c@451
|
93 BOOST_CHECK_EQUAL(key, k);
|
c@451
|
94 }
|
c@451
|
95 }
|
c@451
|
96
|
c@451
|
97 bool minor = (key > 12);
|
c@451
|
98
|
c@451
|
99 int tonic = key;
|
c@451
|
100 if (minor) tonic -= 12;
|
c@451
|
101
|
cannam@470
|
102 BOOST_CHECK_EQUAL(tonic, 1 + (midiPitch % 12));
|
c@451
|
103 }
|
c@451
|
104 }
|
c@451
|
105
|
c@451
|
106 BOOST_AUTO_TEST_SUITE_END()
|