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