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
|
c@451
|
73 cout << endl;
|
c@451
|
74
|
c@451
|
75 GetKeyMode gkm(sampleRate, concertA, 10, 10);
|
c@451
|
76 int blockSize = gkm.getBlockSize();
|
c@451
|
77 int hopSize = gkm.getHopSize();
|
c@451
|
78 cerr << "blockSize = " << blockSize
|
c@451
|
79 << ", hopSize = " << hopSize << endl;
|
c@451
|
80
|
c@451
|
81 double frequency = concertA * pow(2.0, (midiPitch - 69.0) / 12.0);
|
c@451
|
82 cout << "midiPitch = " << midiPitch
|
c@451
|
83 << ", name = " << midiPitchName(midiPitch)
|
c@451
|
84 << ", frequency = " << frequency << endl;
|
c@451
|
85
|
c@451
|
86 int blocks = 4;
|
c@451
|
87 int totalLength = blockSize * blocks;
|
c@451
|
88 vector<double> signal = generateSinusoid(frequency, sampleRate,
|
c@451
|
89 totalLength);
|
c@451
|
90
|
c@451
|
91 int key;
|
c@451
|
92
|
c@451
|
93 for (int offset = 0; offset + blockSize < totalLength;
|
c@451
|
94 offset += hopSize) {
|
c@451
|
95 int k = gkm.process(signal.data() + offset);
|
c@451
|
96 if (offset == 0) {
|
c@451
|
97 key = k;
|
c@451
|
98 } else {
|
c@451
|
99 BOOST_CHECK_EQUAL(key, k);
|
c@451
|
100 }
|
c@451
|
101 }
|
c@451
|
102
|
c@451
|
103 bool minor = (key > 12);
|
c@451
|
104
|
c@451
|
105 int tonic = key;
|
c@451
|
106 if (minor) tonic -= 12;
|
c@451
|
107
|
c@451
|
108 string name = keyName(tonic, minor);
|
c@451
|
109 cout << "key value = " << key << ", name = " << name << endl;
|
c@451
|
110 }
|
c@451
|
111 }
|
c@451
|
112
|
c@451
|
113 BOOST_AUTO_TEST_SUITE_END()
|