Mercurial > hg > constant-q-cpp
comparison src/Chromagram.cpp @ 170:b96b0addbca7
Pull out chroma class into library
author | Chris Cannam <c.cannam@qmul.ac.uk> |
---|---|
date | Wed, 04 Feb 2015 15:09:06 +0000 |
parents | |
children | a12642e36167 |
comparison
equal
deleted
inserted
replaced
169:8a1d240ac542 | 170:b96b0addbca7 |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 /* | |
3 Constant-Q library | |
4 Copyright (c) 2013-2015 Queen Mary, University of London | |
5 | |
6 Permission is hereby granted, free of charge, to any person | |
7 obtaining a copy of this software and associated documentation | |
8 files (the "Software"), to deal in the Software without | |
9 restriction, including without limitation the rights to use, copy, | |
10 modify, merge, publish, distribute, sublicense, and/or sell copies | |
11 of the Software, and to permit persons to whom the Software is | |
12 furnished to do so, subject to the following conditions: | |
13 | |
14 The above copyright notice and this permission notice shall be | |
15 included in all copies or substantial portions of the Software. | |
16 | |
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |
21 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | |
22 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
24 | |
25 Except as contained in this notice, the names of the Centre for | |
26 Digital Music; Queen Mary, University of London; and Chris Cannam | |
27 shall not be used in advertising or otherwise to promote the sale, | |
28 use or other dealings in this Software without prior written | |
29 authorization. | |
30 */ | |
31 | |
32 #include "Chromagram.h" | |
33 #include "CQSpectrogram.h" | |
34 #include "Pitch.h" | |
35 | |
36 #include <cstdio> | |
37 | |
38 using namespace std; | |
39 | |
40 Chromagram::Chromagram(Parameters params) : | |
41 m_params(params), | |
42 m_cq(0) | |
43 { | |
44 int highestOctave = m_params.lowestOctave + m_params.octaves - 1; | |
45 | |
46 int midiPitchLimit = (1 + highestOctave) * 12 + 12; // C just beyond top | |
47 double midiPitchLimitFreq = Pitch::getFrequencyForPitch | |
48 (midiPitchLimit, 0, m_params.tuningFrequency); | |
49 | |
50 // Max frequency is frequency of the MIDI pitch just beyond the | |
51 // top octave range (midiPitchLimit) minus one bin, then minus | |
52 // floor(bins per semitone / 2) | |
53 int bps = m_params.bpo / 12; | |
54 m_maxFrequency = midiPitchLimitFreq / | |
55 pow(2, (1.0 + floor(bps/2)) / m_params.bpo); | |
56 | |
57 // Min frequency is frequency of midiPitchLimit lowered by the | |
58 // appropriate number of octaves. | |
59 m_minFrequency = midiPitchLimitFreq / | |
60 pow(2, m_params.octaves + 1); | |
61 | |
62 CQParameters p | |
63 (params.sampleRate, m_minFrequency, m_maxFrequency, params.bpo); | |
64 | |
65 m_cq = new CQSpectrogram(p, CQSpectrogram::InterpolateLinear); | |
66 } | |
67 | |
68 Chromagram::~Chromagram() | |
69 { | |
70 delete m_cq; | |
71 } | |
72 | |
73 bool | |
74 Chromagram::isValid() const | |
75 { | |
76 return m_cq->isValid(); | |
77 } | |
78 | |
79 int | |
80 Chromagram::getColumnHop() const | |
81 { | |
82 return m_cq->getColumnHop(); | |
83 } | |
84 | |
85 int | |
86 Chromagram::getLatency() const | |
87 { | |
88 return m_cq->getLatency(); | |
89 } | |
90 | |
91 string | |
92 Chromagram::getBinName(int bin) const | |
93 { | |
94 static const char *names[] = { | |
95 "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" | |
96 }; | |
97 | |
98 float freq = m_cq->getBinFrequency(m_params.bpo - bin - 1); | |
99 int note = Pitch::getPitchForFrequency(freq, 0, m_params.tuningFrequency); | |
100 float nearestFreq = | |
101 Pitch::getFrequencyForPitch(note, 0, m_params.tuningFrequency); | |
102 | |
103 char name[40]; | |
104 sprintf(name, "%d", bin); | |
105 if (fabs(freq - nearestFreq) < 0.01) { | |
106 return (name + std::string(" ") + names[note % 12]); | |
107 } else { | |
108 return (name); | |
109 } | |
110 } | |
111 | |
112 CQBase::RealBlock | |
113 Chromagram::process(const CQBase::RealSequence &data) | |
114 { | |
115 return convert(m_cq->process(data)); | |
116 } | |
117 | |
118 CQBase::RealBlock | |
119 Chromagram::getRemainingOutput() | |
120 { | |
121 return convert(m_cq->getRemainingOutput()); | |
122 } | |
123 | |
124 CQBase::RealBlock | |
125 Chromagram::convert(const CQBase::RealBlock &cqout) | |
126 { | |
127 CQBase::RealBlock chroma; | |
128 | |
129 int width = cqout.size(); | |
130 | |
131 for (int i = 0; i < width; ++i) { | |
132 | |
133 CQBase::RealSequence column(m_params.bpo, 0.); | |
134 | |
135 // fold and invert to put low frequencies at the start | |
136 | |
137 int thisHeight = cqout[i].size(); | |
138 | |
139 for (int j = 0; j < thisHeight; ++j) { | |
140 column[m_params.bpo - (j % m_params.bpo) - 1] += cqout[i][j]; | |
141 } | |
142 | |
143 chroma.push_back(column); | |
144 } | |
145 | |
146 return chroma; | |
147 } | |
148 |