annotate tests/TestGetKeyMode.cpp @ 222:0990c1cb4049 chroma-key-tuning-review

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