annotate ConstrainedHarmonicPeak.cpp @ 4:3bf29717cc01

m_blockSize -> m_fftSize (they happen to be the same in this case, but that's what we use it as)
author Chris Cannam
date Fri, 07 Mar 2014 16:20:59 +0000
parents ab0b04e1c56b
children e9b629578488
rev   line source
Chris@0 1
Chris@0 2 #include "ConstrainedHarmonicPeak.h"
Chris@0 3
Chris@0 4 #include <cmath>
Chris@0 5 #include <cstdio>
Chris@0 6
Chris@0 7 using std::cerr;
Chris@0 8 using std::endl;
Chris@0 9 using std::vector;
Chris@0 10
Chris@0 11 ConstrainedHarmonicPeak::ConstrainedHarmonicPeak(float inputSampleRate) :
Chris@0 12 Plugin(inputSampleRate),
Chris@4 13 m_fftSize(0),
Chris@0 14 m_minFreq(0),
Chris@1 15 m_maxFreq(inputSampleRate/2),
Chris@1 16 m_harmonics(5)
Chris@0 17 {
Chris@0 18 }
Chris@0 19
Chris@0 20 ConstrainedHarmonicPeak::~ConstrainedHarmonicPeak()
Chris@0 21 {
Chris@0 22 }
Chris@0 23
Chris@0 24 string
Chris@0 25 ConstrainedHarmonicPeak::getIdentifier() const
Chris@0 26 {
Chris@0 27 return "constrainedharmonicpeak";
Chris@0 28 }
Chris@0 29
Chris@0 30 string
Chris@0 31 ConstrainedHarmonicPeak::getName() const
Chris@0 32 {
Chris@0 33 return "Frequency-Constrained Harmonic Peak";
Chris@0 34 }
Chris@0 35
Chris@0 36 string
Chris@0 37 ConstrainedHarmonicPeak::getDescription() const
Chris@0 38 {
Chris@0 39 //!!! Return something helpful here!
Chris@0 40 return "";
Chris@0 41 }
Chris@0 42
Chris@0 43 string
Chris@0 44 ConstrainedHarmonicPeak::getMaker() const
Chris@0 45 {
Chris@0 46 return "Queen Mary, University of London";
Chris@0 47 }
Chris@0 48
Chris@0 49 int
Chris@0 50 ConstrainedHarmonicPeak::getPluginVersion() const
Chris@0 51 {
Chris@0 52 return 1;
Chris@0 53 }
Chris@0 54
Chris@0 55 string
Chris@0 56 ConstrainedHarmonicPeak::getCopyright() const
Chris@0 57 {
Chris@0 58 return "GPL";
Chris@0 59 }
Chris@0 60
Chris@0 61 ConstrainedHarmonicPeak::InputDomain
Chris@0 62 ConstrainedHarmonicPeak::getInputDomain() const
Chris@0 63 {
Chris@0 64 return FrequencyDomain;
Chris@0 65 }
Chris@0 66
Chris@0 67 size_t
Chris@0 68 ConstrainedHarmonicPeak::getPreferredBlockSize() const
Chris@0 69 {
Chris@0 70 return 2048;
Chris@0 71 }
Chris@0 72
Chris@0 73 size_t
Chris@0 74 ConstrainedHarmonicPeak::getPreferredStepSize() const
Chris@0 75 {
Chris@0 76 return 512;
Chris@0 77 }
Chris@0 78
Chris@0 79 size_t
Chris@0 80 ConstrainedHarmonicPeak::getMinChannelCount() const
Chris@0 81 {
Chris@0 82 return 1;
Chris@0 83 }
Chris@0 84
Chris@0 85 size_t
Chris@0 86 ConstrainedHarmonicPeak::getMaxChannelCount() const
Chris@0 87 {
Chris@0 88 return 1;
Chris@0 89 }
Chris@0 90
Chris@0 91 ConstrainedHarmonicPeak::ParameterList
Chris@0 92 ConstrainedHarmonicPeak::getParameterDescriptors() const
Chris@0 93 {
Chris@0 94 ParameterList list;
Chris@0 95
Chris@0 96 ParameterDescriptor d;
Chris@0 97 d.identifier = "minfreq";
Chris@0 98 d.name = "Minimum frequency";
Chris@0 99 d.description = "";
Chris@0 100 d.unit = "Hz";
Chris@0 101 d.minValue = 0;
Chris@0 102 d.maxValue = m_inputSampleRate/2;
Chris@0 103 d.defaultValue = 0;
Chris@0 104 d.isQuantized = false;
Chris@0 105 list.push_back(d);
Chris@0 106
Chris@0 107 d.identifier = "maxfreq";
Chris@0 108 d.name = "Maximum frequency";
Chris@0 109 d.description = "";
Chris@0 110 d.unit = "Hz";
Chris@0 111 d.minValue = 0;
Chris@0 112 d.maxValue = m_inputSampleRate/2;
Chris@0 113 d.defaultValue = 0;
Chris@0 114 d.isQuantized = false;
Chris@0 115 list.push_back(d);
Chris@0 116
Chris@1 117 d.identifier = "harmonics";
Chris@1 118 d.name = "Harmonics";
Chris@1 119 d.description = "Maximum number of harmonics to consider";
Chris@1 120 d.unit = "";
Chris@1 121 d.minValue = 1;
Chris@1 122 d.maxValue = 20;
Chris@1 123 d.defaultValue = 5;
Chris@1 124 d.isQuantized = true;
Chris@1 125 d.quantizeStep = 1;
Chris@1 126 list.push_back(d);
Chris@1 127
Chris@0 128 return list;
Chris@0 129 }
Chris@0 130
Chris@0 131 float
Chris@0 132 ConstrainedHarmonicPeak::getParameter(string identifier) const
Chris@0 133 {
Chris@0 134 if (identifier == "minfreq") {
Chris@0 135 return m_minFreq;
Chris@0 136 } else if (identifier == "maxfreq") {
Chris@0 137 return m_maxFreq;
Chris@1 138 } else if (identifier == "harmonics") {
Chris@1 139 return m_harmonics;
Chris@0 140 }
Chris@0 141 return 0;
Chris@0 142 }
Chris@0 143
Chris@0 144 void
Chris@0 145 ConstrainedHarmonicPeak::setParameter(string identifier, float value)
Chris@0 146 {
Chris@0 147 if (identifier == "minfreq") {
Chris@0 148 m_minFreq = value;
Chris@0 149 } else if (identifier == "maxfreq") {
Chris@0 150 m_maxFreq = value;
Chris@1 151 } else if (identifier == "harmonics") {
Chris@1 152 m_harmonics = int(round(value));
Chris@0 153 }
Chris@0 154 }
Chris@0 155
Chris@0 156 ConstrainedHarmonicPeak::ProgramList
Chris@0 157 ConstrainedHarmonicPeak::getPrograms() const
Chris@0 158 {
Chris@0 159 ProgramList list;
Chris@0 160 return list;
Chris@0 161 }
Chris@0 162
Chris@0 163 string
Chris@0 164 ConstrainedHarmonicPeak::getCurrentProgram() const
Chris@0 165 {
Chris@0 166 return ""; // no programs
Chris@0 167 }
Chris@0 168
Chris@0 169 void
Chris@0 170 ConstrainedHarmonicPeak::selectProgram(string name)
Chris@0 171 {
Chris@0 172 }
Chris@0 173
Chris@0 174 ConstrainedHarmonicPeak::OutputList
Chris@0 175 ConstrainedHarmonicPeak::getOutputDescriptors() const
Chris@0 176 {
Chris@0 177 OutputList list;
Chris@0 178
Chris@0 179 OutputDescriptor d;
Chris@0 180 d.identifier = "peak";
Chris@0 181 d.name = "Peak frequency";
Chris@0 182 d.description = "";
Chris@0 183 d.unit = "Hz";
Chris@0 184 d.sampleType = OutputDescriptor::OneSamplePerStep;
Chris@0 185 d.hasDuration = false;
Chris@0 186 list.push_back(d);
Chris@0 187
Chris@0 188 return list;
Chris@0 189 }
Chris@0 190
Chris@0 191 bool
Chris@0 192 ConstrainedHarmonicPeak::initialise(size_t channels, size_t stepSize, size_t blockSize)
Chris@0 193 {
Chris@0 194 if (channels < getMinChannelCount() ||
Chris@0 195 channels > getMaxChannelCount()) {
Chris@0 196 cerr << "ConstrainedHarmonicPeak::initialise: ERROR: channels " << channels
Chris@0 197 << " out of acceptable range " << getMinChannelCount()
Chris@0 198 << " -> " << getMaxChannelCount() << endl;
Chris@0 199 return false;
Chris@0 200 }
Chris@0 201
Chris@4 202 m_fftSize = blockSize;
Chris@0 203
Chris@0 204 return true;
Chris@0 205 }
Chris@0 206
Chris@0 207 void
Chris@0 208 ConstrainedHarmonicPeak::reset()
Chris@0 209 {
Chris@0 210 }
Chris@0 211
Chris@1 212 double
Chris@1 213 ConstrainedHarmonicPeak::findInterpolatedPeak(const double *in,
Chris@1 214 int peakbin,
Chris@1 215 int bins)
Chris@1 216 {
Chris@1 217 // duplicate with SimpleCepstrum plugin
Chris@1 218 // after jos,
Chris@1 219 // https://ccrma.stanford.edu/~jos/sasp/Quadratic_Interpolation_Spectral_Peaks.html
Chris@1 220
Chris@1 221 if (peakbin < 1 || peakbin > bins - 2) {
Chris@1 222 return peakbin;
Chris@1 223 }
Chris@1 224
Chris@1 225 double alpha = in[peakbin-1];
Chris@1 226 double beta = in[peakbin];
Chris@1 227 double gamma = in[peakbin+1];
Chris@1 228
Chris@1 229 double denom = (alpha - 2*beta + gamma);
Chris@1 230
Chris@1 231 if (denom == 0) {
Chris@1 232 // flat
Chris@1 233 return peakbin;
Chris@1 234 }
Chris@1 235
Chris@1 236 double p = ((alpha - gamma) / denom) / 2.0;
Chris@1 237
Chris@1 238 return double(peakbin) + p;
Chris@1 239 }
Chris@1 240
Chris@0 241 ConstrainedHarmonicPeak::FeatureSet
Chris@0 242 ConstrainedHarmonicPeak::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
Chris@0 243 {
Chris@0 244 FeatureSet fs;
Chris@0 245
Chris@4 246 int hs = m_fftSize/2;
Chris@1 247
Chris@1 248 double *mags = new double[hs+1];
Chris@1 249 for (int i = 0; i <= hs; ++i) {
Chris@4 250 mags[i] = sqrt(inputBuffers[0][i*2] * inputBuffers[0][i*2] +
Chris@4 251 inputBuffers[0][i*2+1] * inputBuffers[0][i*2+1]);
Chris@1 252 }
Chris@1 253
Chris@1 254 // bin freq is bin * samplerate / fftsize
Chris@1 255
Chris@4 256 int minbin = int(floor((m_minFreq * m_fftSize) / m_inputSampleRate));
Chris@4 257 int maxbin = int(ceil((m_maxFreq * m_fftSize) / m_inputSampleRate));
Chris@1 258 if (minbin > hs) minbin = hs;
Chris@1 259 if (maxbin > hs) maxbin = hs;
Chris@1 260 if (maxbin <= minbin) return fs;
Chris@1 261
Chris@1 262 double *hps = new double[maxbin - minbin + 1];
Chris@1 263
Chris@1 264 // HPS in dB after MzHarmonicSpectrum
Chris@1 265
Chris@1 266 for (int bin = minbin; bin <= maxbin; ++bin) {
Chris@1 267
Chris@1 268 int i = bin - minbin;
Chris@1 269 hps[i] = 1.0;
Chris@1 270
Chris@1 271 int contributing = 0;
Chris@1 272
Chris@1 273 for (int j = 1; j <= m_harmonics; ++j) {
Chris@1 274 if (j * bin > hs) break;
Chris@1 275 hps[i] *= mags[j * bin];
Chris@1 276 ++contributing;
Chris@1 277 }
Chris@1 278
Chris@1 279 if (hps[i] <= 0.0) {
Chris@1 280 hps[i] = -120.0;
Chris@1 281 } else {
Chris@1 282 hps[i] = 20.0 / contributing * log10(hps[i]);
Chris@1 283 }
Chris@1 284 }
Chris@1 285
Chris@1 286 double maxdb = -120.0;
Chris@1 287 int maxidx = 0;
Chris@1 288 for (int i = 0; i <= maxbin - minbin; ++i) {
Chris@1 289 if (hps[i] > maxdb) {
Chris@1 290 maxdb = hps[i];
Chris@1 291 maxidx = i;
Chris@1 292 }
Chris@1 293 }
Chris@1 294
Chris@1 295 double interpolated = findInterpolatedPeak(hps, maxidx, maxbin - minbin + 1);
Chris@1 296 interpolated = interpolated + minbin;
Chris@1 297
Chris@4 298 double freq = interpolated * m_inputSampleRate / m_fftSize;
Chris@1 299
Chris@1 300 Feature f;
Chris@1 301 f.values.push_back(freq);
Chris@1 302 fs[0].push_back(f);
Chris@1 303
Chris@0 304 return fs;
Chris@0 305 }
Chris@0 306
Chris@0 307 ConstrainedHarmonicPeak::FeatureSet
Chris@0 308 ConstrainedHarmonicPeak::getRemainingFeatures()
Chris@0 309 {
Chris@0 310 FeatureSet fs;
Chris@0 311 return fs;
Chris@0 312 }
Chris@0 313