annotate vamp/CQVamp.cpp @ 53:a25abb7a21c0

Further tidying, compensate for latency in Vamp plugin
author Chris Cannam <c.cannam@qmul.ac.uk>
date Thu, 28 Nov 2013 11:46:39 +0000
parents cb072f01435b
children 2a21b4506d7f
rev   line source
c@35 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@35 2
c@35 3 #include "CQVamp.h"
c@35 4
c@35 5 #include "../cpp-qm-dsp/ConstantQ.h"
c@35 6
c@35 7 using std::string;
c@35 8 using std::vector;
c@35 9 using std::cerr;
c@35 10 using std::endl;
c@35 11
c@35 12 CQVamp::CQVamp(float inputSampleRate) :
c@35 13 Vamp::Plugin(inputSampleRate),
c@35 14 m_cq(0),
c@35 15 m_maxFrequency(inputSampleRate/2),
c@35 16 m_minFrequency(46),
c@53 17 m_bpo(24),
c@53 18 m_haveStartTime(false),
c@53 19 m_columnCount(0)
c@35 20 {
c@35 21 }
c@35 22
c@35 23 CQVamp::~CQVamp()
c@35 24 {
c@35 25 delete m_cq;
c@35 26 }
c@35 27
c@35 28 string
c@35 29 CQVamp::getIdentifier() const
c@35 30 {
c@35 31 return "cqvamp";
c@35 32 }
c@35 33
c@35 34 string
c@35 35 CQVamp::getName() const
c@35 36 {
c@35 37 return "Constant-Q Spectrogram";
c@35 38 }
c@35 39
c@35 40 string
c@35 41 CQVamp::getDescription() const
c@35 42 {
c@35 43 return "Extract a spectrogram with constant ratio of centre frequency to resolution from the input audio";
c@35 44 }
c@35 45
c@35 46 string
c@35 47 CQVamp::getMaker() const
c@35 48 {
c@35 49 return "Queen Mary, University of London";
c@35 50 }
c@35 51
c@35 52 int
c@35 53 CQVamp::getPluginVersion() const
c@35 54 {
c@35 55 return 1;
c@35 56 }
c@35 57
c@35 58 string
c@35 59 CQVamp::getCopyright() const
c@35 60 {
c@35 61 return "Plugin by Chris Cannam. Method by Christian Schörkhuber and Anssi Klapuri. Copyright (c) 2013 QMUL";
c@35 62 }
c@35 63
c@35 64 CQVamp::ParameterList
c@35 65 CQVamp::getParameterDescriptors() const
c@35 66 {
c@35 67 ParameterList list;
c@35 68
c@35 69 ParameterDescriptor desc;
c@35 70 desc.identifier = "minfreq";
c@35 71 desc.name = "Minimum Frequency";
c@35 72 desc.unit = "Hz";
c@35 73 desc.description = "Hint for the lowest frequency to be included in the constant-Q transform. The actual frequency range will be an integral number of octaves ending at the highest frequency specified";
c@35 74 desc.minValue = 10;
c@35 75 desc.maxValue = m_inputSampleRate/2;
c@35 76 desc.defaultValue = 46;
c@35 77 desc.isQuantized = false;
c@35 78 list.push_back(desc);
c@35 79
c@35 80 desc.identifier = "maxfreq";
c@35 81 desc.name = "Maximum Frequency";
c@35 82 desc.unit = "Hz";
c@35 83 desc.description = "Highest frequency to be included in the constant-Q transform";
c@35 84 desc.minValue = 10;
c@35 85 desc.maxValue = m_inputSampleRate/2;
c@35 86 desc.defaultValue = m_inputSampleRate/2;
c@35 87 desc.isQuantized = false;
c@35 88 list.push_back(desc);
c@35 89
c@35 90 desc.identifier = "bpo";
c@35 91 desc.name = "Bins per Octave";
c@35 92 desc.unit = "bins";
c@35 93 desc.description = "Number of constant-Q transform bins per octave";
c@35 94 desc.minValue = 2;
c@35 95 desc.maxValue = 480;
c@35 96 desc.defaultValue = 24;
c@35 97 desc.isQuantized = true;
c@35 98 desc.quantizeStep = 1;
c@35 99 list.push_back(desc);
c@35 100
c@35 101 return list;
c@35 102 }
c@35 103
c@35 104 float
c@35 105 CQVamp::getParameter(std::string param) const
c@35 106 {
c@35 107 if (param == "minfreq") {
c@35 108 return m_minFrequency;
c@35 109 }
c@35 110 if (param == "maxfreq") {
c@35 111 return m_maxFrequency;
c@35 112 }
c@35 113 if (param == "bpo") {
c@35 114 return m_bpo;
c@35 115 }
c@35 116 std::cerr << "WARNING: CQVamp::getParameter: unknown parameter \""
c@35 117 << param << "\"" << std::endl;
c@35 118 return 0.0;
c@35 119 }
c@35 120
c@35 121 void
c@35 122 CQVamp::setParameter(std::string param, float value)
c@35 123 {
c@35 124 if (param == "minfreq") {
c@35 125 m_minFrequency = value;
c@35 126 } else if (param == "maxfreq") {
c@35 127 m_maxFrequency = value;
c@35 128 } else if (param == "bpo") {
c@35 129 m_bpo = lrintf(value);
c@35 130 } else {
c@35 131 std::cerr << "WARNING: CQVamp::setParameter: unknown parameter \""
c@35 132 << param << "\"" << std::endl;
c@35 133 }
c@35 134 }
c@35 135
c@35 136 bool
c@35 137 CQVamp::initialise(size_t channels, size_t stepSize, size_t blockSize)
c@35 138 {
c@35 139 if (m_cq) {
c@35 140 delete m_cq;
c@35 141 m_cq = 0;
c@35 142 }
c@35 143
c@35 144 if (channels < getMinChannelCount() ||
c@35 145 channels > getMaxChannelCount()) return false;
c@35 146
c@35 147 m_stepSize = stepSize;
c@35 148 m_blockSize = blockSize;
c@35 149
c@35 150 m_cq = new ConstantQ
c@35 151 (m_inputSampleRate, m_minFrequency, m_maxFrequency, m_bpo);
c@35 152
c@35 153 return true;
c@35 154 }
c@35 155
c@35 156 void
c@35 157 CQVamp::reset()
c@35 158 {
c@35 159 if (m_cq) {
c@35 160 delete m_cq;
c@35 161 m_cq = new ConstantQ
c@35 162 (m_inputSampleRate, m_minFrequency, m_maxFrequency, m_bpo);
c@35 163 }
c@36 164 m_prevFeature.clear();
c@53 165 m_haveStartTime = false;
c@53 166 m_columnCount = 0;
c@35 167 }
c@35 168
c@35 169 size_t
c@35 170 CQVamp::getPreferredStepSize() const
c@35 171 {
c@35 172 return 0;
c@35 173 }
c@35 174
c@35 175 size_t
c@35 176 CQVamp::getPreferredBlockSize() const
c@35 177 {
c@35 178 return 0;
c@35 179 }
c@35 180
c@35 181 CQVamp::OutputList
c@35 182 CQVamp::getOutputDescriptors() const
c@35 183 {
c@35 184 OutputList list;
c@35 185
c@35 186 OutputDescriptor d;
c@35 187 d.identifier = "constantq";
c@35 188 d.name = "Constant-Q Spectrogram";
c@35 189 d.unit = "";
c@35 190 d.description = "Output of constant-Q transform, as a single vector per process block";
c@35 191 d.hasFixedBinCount = true;
c@35 192 d.binCount = (m_cq ? m_cq->getTotalBins() : (9 * 24));
c@35 193 d.hasKnownExtents = false;
c@35 194 d.isQuantized = false;
c@35 195 d.sampleType = OutputDescriptor::FixedSampleRate;
c@35 196 d.sampleRate = m_inputSampleRate / (m_cq ? m_cq->getColumnHop() : 256);
c@35 197 list.push_back(d);
c@35 198
c@35 199 return list;
c@35 200 }
c@35 201
c@35 202 CQVamp::FeatureSet
c@35 203 CQVamp::process(const float *const *inputBuffers,
c@53 204 Vamp::RealTime timestamp)
c@35 205 {
c@35 206 if (!m_cq) {
c@35 207 cerr << "ERROR: CQVamp::process: "
c@35 208 << "Plugin has not been initialised"
c@35 209 << endl;
c@35 210 return FeatureSet();
c@35 211 }
c@35 212
c@53 213 if (!m_haveStartTime) {
c@53 214 m_startTime = timestamp;
c@53 215 m_haveStartTime = true;
c@53 216 }
c@53 217
c@35 218 vector<double> data;
c@35 219 for (int i = 0; i < m_blockSize; ++i) data.push_back(inputBuffers[0][i]);
c@35 220
c@35 221 vector<vector<double> > cqout = m_cq->process(data);
c@36 222 return convertToFeatures(cqout);
c@36 223 }
c@35 224
c@36 225 CQVamp::FeatureSet
c@36 226 CQVamp::getRemainingFeatures()
c@36 227 {
c@36 228 vector<vector<double> > cqout = m_cq->getRemainingBlocks();
c@36 229 return convertToFeatures(cqout);
c@36 230 }
c@36 231
c@36 232 CQVamp::FeatureSet
c@36 233 CQVamp::convertToFeatures(const vector<vector<double> > &cqout)
c@36 234 {
c@35 235 FeatureSet returnFeatures;
c@35 236
c@36 237 for (int i = 0; i < (int)cqout.size(); ++i) {
c@35 238
c@35 239 vector<float> column(m_cq->getTotalBins(), 0.f);
c@36 240
c@36 241 for (int j = 0; j < (int)cqout[i].size(); ++j) {
c@35 242 column[j] = cqout[i][j];
c@35 243 }
c@36 244 for (int j = cqout[i].size(); j < m_cq->getTotalBins(); ++j) {
c@36 245 if (j < (int)m_prevFeature.size()) {
c@36 246 column[j] = m_prevFeature[j];
c@36 247 }
c@36 248 }
c@36 249
c@36 250 m_prevFeature = column;
c@35 251
c@35 252 Feature feature;
c@53 253 feature.hasTimestamp = true;
c@53 254 feature.timestamp = m_startTime + Vamp::RealTime::frame2RealTime
c@53 255 (m_columnCount * m_cq->getColumnHop() - m_cq->getLatency(),
c@53 256 m_inputSampleRate);
c@35 257 feature.values = column;
c@35 258 feature.label = "";
c@53 259
c@53 260 cerr << "timestamp = " << feature.timestamp << " (latency = " << m_cq->getLatency() << ", sample rate " << m_inputSampleRate << ")" << endl;
c@53 261
c@53 262 if (feature.timestamp >= m_startTime) {
c@53 263 returnFeatures[0].push_back(feature);
c@53 264 }
c@53 265
c@53 266 ++m_columnCount;
c@35 267 }
c@35 268
c@35 269 return returnFeatures;
c@35 270 }
c@35 271