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