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