c@135
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
c@135
|
2
|
c@135
|
3 #include "cq/CQSpectrogram.h"
|
c@135
|
4
|
c@135
|
5 #include "dsp/Window.h"
|
c@135
|
6
|
c@135
|
7 #include <cmath>
|
c@135
|
8 #include <vector>
|
c@135
|
9 #include <iostream>
|
c@135
|
10
|
c@135
|
11 using std::vector;
|
c@135
|
12 using std::cerr;
|
c@135
|
13 using std::endl;
|
c@135
|
14
|
c@135
|
15 #define BOOST_TEST_DYN_LINK
|
c@135
|
16 #define BOOST_TEST_MAIN
|
c@135
|
17
|
c@135
|
18 #include <boost/test/unit_test.hpp>
|
c@135
|
19
|
c@135
|
20 BOOST_AUTO_TEST_SUITE(TestCQTime)
|
c@135
|
21
|
c@135
|
22 // Principle: Run a Dirac impulse through the CQ transform and check
|
c@135
|
23 // that its output has all the peak bins aligned correctly in time.
|
c@135
|
24
|
c@135
|
25 // Set up fs/2 = 50, frequency range 10 -> 40 i.e. 2 octaves, fixed
|
c@135
|
26 // duration of 2 seconds
|
c@135
|
27 static const double sampleRate = 100;
|
c@135
|
28 static const double cqmin = 10;
|
c@135
|
29 static const double cqmax = 40;
|
c@135
|
30 static const double bpo = 4;
|
c@135
|
31 static const int duration = sampleRate * 2;
|
c@135
|
32
|
c@135
|
33 // Threshold below which to ignore a column completely
|
c@135
|
34 static const double threshold = 0.08;
|
c@135
|
35
|
c@135
|
36 void
|
c@135
|
37 testCQTime(double t)
|
c@135
|
38 {
|
c@135
|
39 vector<CQSpectrogram::Interpolation> interpolationTypes;
|
c@135
|
40 interpolationTypes.push_back(CQSpectrogram::InterpolateZeros);
|
c@135
|
41 interpolationTypes.push_back(CQSpectrogram::InterpolateHold);
|
c@135
|
42 interpolationTypes.push_back(CQSpectrogram::InterpolateLinear);
|
c@135
|
43
|
c@135
|
44 for (int k = 0; k < int(interpolationTypes.size()); ++k) {
|
c@135
|
45
|
c@139
|
46 CQSpectrogram::Interpolation interp = interpolationTypes[k];
|
c@139
|
47
|
c@135
|
48 CQParameters params(sampleRate, cqmin, cqmax, bpo);
|
c@139
|
49 CQSpectrogram cq(params, interp);
|
c@135
|
50
|
c@135
|
51 BOOST_CHECK_EQUAL(cq.getBinsPerOctave(), bpo);
|
c@135
|
52 BOOST_CHECK_EQUAL(cq.getOctaves(), 2);
|
c@135
|
53
|
c@139
|
54 vector<double> input(duration, 0.0);
|
c@139
|
55 int ix = int(floor(t * sampleRate));
|
c@139
|
56 if (ix >= duration) ix = duration-1;
|
c@139
|
57 input[ix] = 1.0;
|
c@135
|
58
|
c@135
|
59 CQSpectrogram::RealBlock output = cq.process(input);
|
c@135
|
60 CQSpectrogram::RealBlock rest = cq.getRemainingOutput();
|
c@135
|
61 output.insert(output.end(), rest.begin(), rest.end());
|
c@135
|
62
|
c@135
|
63 BOOST_CHECK_EQUAL(output[0].size(),
|
c@135
|
64 cq.getBinsPerOctave() * cq.getOctaves());
|
c@135
|
65
|
c@141
|
66 vector<int> peaks;
|
c@141
|
67 double eps = 1e-8;
|
c@141
|
68
|
c@139
|
69 for (int j = 0; j < int(output[0].size()); ++j) {
|
c@139
|
70
|
c@139
|
71 int maxidx = -1;
|
c@139
|
72 double max = 0.0;
|
c@139
|
73 for (int i = 0; i < int(output.size()); ++i) {
|
c@139
|
74 double value = output[i][j];
|
c@141
|
75 if (i == 0 || value + eps > max) {
|
c@139
|
76 max = value;
|
c@139
|
77 maxidx = i;
|
c@139
|
78 }
|
c@139
|
79 }
|
c@139
|
80
|
c@141
|
81 peaks.push_back(maxidx);
|
c@141
|
82 }
|
c@139
|
83
|
c@141
|
84 for (int j = 1; j < int(peaks.size()); ++j) {
|
c@141
|
85 int oct = j / bpo;
|
c@141
|
86 int spacing = (1 << oct);
|
c@141
|
87 int actual = peaks[j]/spacing;
|
c@141
|
88 int expected = int(round(double(peaks[0])/spacing));
|
c@141
|
89 if (actual != expected) {
|
c@139
|
90 cerr << "ERROR: In row " << j << " (bin freq "
|
c@139
|
91 << cq.getBinFrequency(j) << "), interpolation " << interp
|
c@139
|
92 << ", maximum value for time " << t
|
c@141
|
93 << "\n found at index " << peaks[j]
|
c@141
|
94 << " of " << output.size() << " which does not align with"
|
c@141
|
95 << " highest frequency\n bin peak at " << peaks[0]
|
c@141
|
96 << " given octave spacing of " << spacing
|
c@141
|
97 << "\n [latency = " << cq.getLatency()
|
c@139
|
98 << ", hop = " << cq.getColumnHop() << ", duration = "
|
c@141
|
99 << duration << ", ix = " << ix << "]" << endl;
|
c@139
|
100 cerr << "row contains: ";
|
c@139
|
101 for (int i = 0; i < int(output.size()); ++i) {
|
c@141
|
102 if (i == expected * spacing) cerr << "*";
|
c@141
|
103 if (i == peaks[j]) cerr << "**";
|
c@139
|
104 cerr << output[i][j] << " ";
|
c@139
|
105 }
|
c@139
|
106 cerr << endl;
|
c@139
|
107
|
c@141
|
108 BOOST_CHECK_EQUAL(actual, expected);
|
c@139
|
109 }
|
c@139
|
110 }
|
c@135
|
111 }
|
c@135
|
112 }
|
c@135
|
113
|
c@135
|
114 BOOST_AUTO_TEST_CASE(time_zero) { testCQTime(0); }
|
c@135
|
115 BOOST_AUTO_TEST_CASE(time_half) { testCQTime(0.5); }
|
c@135
|
116 BOOST_AUTO_TEST_CASE(time_one) { testCQTime(1.0); }
|
c@135
|
117 BOOST_AUTO_TEST_CASE(time_two) { testCQTime(2.0); }
|
c@135
|
118
|
c@135
|
119 BOOST_AUTO_TEST_SUITE_END()
|
c@135
|
120
|