annotate NNLSChroma.cpp @ 35:cf8898a0174c matthiasm-plugin

* Split out NNLSChroma plugin into three plugins (chroma, chordino, tuning) with a common base class. There's still quite a lot of duplication between the getRemainingFeatures functions. Also add copyright / copying headers, etc.
author Chris Cannam
date Fri, 22 Oct 2010 11:30:21 +0100
parents da3195577172
children 3c261b864e49
rev   line source
Chris@23 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
matthiasm@0 2
Chris@35 3 /*
Chris@35 4 NNLS-Chroma / Chordino
Chris@35 5
Chris@35 6 Audio feature extraction plugins for chromagram and chord
Chris@35 7 estimation.
Chris@35 8
Chris@35 9 Centre for Digital Music, Queen Mary University of London.
Chris@35 10 This file copyright 2008-2010 Matthias Mauch and QMUL.
Chris@35 11
Chris@35 12 This program is free software; you can redistribute it and/or
Chris@35 13 modify it under the terms of the GNU General Public License as
Chris@35 14 published by the Free Software Foundation; either version 2 of the
Chris@35 15 License, or (at your option) any later version. See the file
Chris@35 16 COPYING included with this distribution for more information.
Chris@35 17 */
Chris@35 18
matthiasm@0 19 #include "NNLSChroma.h"
Chris@27 20
Chris@27 21 #include "chromamethods.h"
Chris@27 22
Chris@27 23 #include <cstdlib>
Chris@27 24 #include <fstream>
matthiasm@0 25 #include <cmath>
matthiasm@9 26
Chris@27 27 #include <algorithm>
matthiasm@0 28
matthiasm@0 29 const bool debug_on = false;
matthiasm@0 30
Chris@27 31 const vector<float> hw(hammingwind, hammingwind+19);
matthiasm@0 32
matthiasm@0 33 NNLSChroma::NNLSChroma(float inputSampleRate) :
Chris@35 34 NNLSBase(inputSampleRate)
matthiasm@0 35 {
Chris@23 36 if (debug_on) cerr << "--> NNLSChroma" << endl;
matthiasm@0 37 }
matthiasm@0 38
matthiasm@0 39 NNLSChroma::~NNLSChroma()
matthiasm@0 40 {
Chris@23 41 if (debug_on) cerr << "--> ~NNLSChroma" << endl;
matthiasm@0 42 }
matthiasm@0 43
matthiasm@0 44 string
matthiasm@0 45 NNLSChroma::getIdentifier() const
matthiasm@0 46 {
Chris@23 47 if (debug_on) cerr << "--> getIdentifier" << endl;
matthiasm@0 48 return "nnls_chroma";
matthiasm@0 49 }
matthiasm@0 50
matthiasm@0 51 string
matthiasm@0 52 NNLSChroma::getName() const
matthiasm@0 53 {
Chris@23 54 if (debug_on) cerr << "--> getName" << endl;
matthiasm@0 55 return "NNLS Chroma";
matthiasm@0 56 }
matthiasm@0 57
matthiasm@0 58 string
matthiasm@0 59 NNLSChroma::getDescription() const
matthiasm@0 60 {
Chris@23 61 if (debug_on) cerr << "--> getDescription" << endl;
matthiasm@13 62 return "This plugin provides a number of features derived from a log-frequency amplitude spectrum of the DFT: some variants of the log-frequency spectrum, including a semitone spectrum derived from approximate transcription using the NNLS algorithm; based on this semitone spectrum, chroma features and a simple chord estimate.";
matthiasm@0 63 }
matthiasm@0 64
matthiasm@0 65 NNLSChroma::OutputList
matthiasm@0 66 NNLSChroma::getOutputDescriptors() const
matthiasm@0 67 {
Chris@23 68 if (debug_on) cerr << "--> getOutputDescriptors" << endl;
matthiasm@0 69 OutputList list;
matthiasm@0 70
matthiasm@0 71 // Make chroma names for the binNames property
matthiasm@0 72 vector<string> chromanames;
matthiasm@0 73 vector<string> bothchromanames;
matthiasm@0 74 for (int iNote = 0; iNote < 24; iNote++) {
matthiasm@0 75 bothchromanames.push_back(notenames[iNote]);
matthiasm@0 76 if (iNote < 12) {
matthiasm@0 77 chromanames.push_back(notenames[iNote]);
matthiasm@0 78 }
matthiasm@0 79 }
matthiasm@0 80
Chris@35 81 int index = 0;
matthiasm@0 82
Chris@23 83 OutputDescriptor d1;
matthiasm@0 84 d1.identifier = "logfreqspec";
matthiasm@0 85 d1.name = "Log-Frequency Spectrum";
matthiasm@0 86 d1.description = "A Log-Frequency Spectrum (constant Q) that is obtained by cosine filter mapping.";
matthiasm@0 87 d1.unit = "";
matthiasm@0 88 d1.hasFixedBinCount = true;
matthiasm@0 89 d1.binCount = nNote;
matthiasm@0 90 d1.hasKnownExtents = false;
matthiasm@0 91 d1.isQuantized = false;
matthiasm@0 92 d1.sampleType = OutputDescriptor::FixedSampleRate;
matthiasm@0 93 d1.hasDuration = false;
matthiasm@0 94 d1.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
matthiasm@0 95 list.push_back(d1);
Chris@35 96 m_outputLogSpec = index++;
matthiasm@0 97
Chris@23 98 OutputDescriptor d2;
matthiasm@0 99 d2.identifier = "tunedlogfreqspec";
matthiasm@0 100 d2.name = "Tuned Log-Frequency Spectrum";
matthiasm@0 101 d2.description = "A Log-Frequency Spectrum (constant Q) that is obtained by cosine filter mapping, then its tuned using the estimated tuning frequency.";
matthiasm@0 102 d2.unit = "";
matthiasm@0 103 d2.hasFixedBinCount = true;
matthiasm@0 104 d2.binCount = 256;
matthiasm@0 105 d2.hasKnownExtents = false;
matthiasm@0 106 d2.isQuantized = false;
matthiasm@0 107 d2.sampleType = OutputDescriptor::FixedSampleRate;
matthiasm@0 108 d2.hasDuration = false;
matthiasm@0 109 d2.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
matthiasm@0 110 list.push_back(d2);
Chris@35 111 m_outputTunedSpec = index++;
matthiasm@0 112
matthiasm@0 113 OutputDescriptor d3;
matthiasm@0 114 d3.identifier = "semitonespectrum";
matthiasm@0 115 d3.name = "Semitone Spectrum";
matthiasm@0 116 d3.description = "A semitone-spaced log-frequency spectrum derived from the third-of-a-semitone-spaced tuned log-frequency spectrum.";
matthiasm@0 117 d3.unit = "";
matthiasm@0 118 d3.hasFixedBinCount = true;
matthiasm@0 119 d3.binCount = 84;
matthiasm@0 120 d3.hasKnownExtents = false;
matthiasm@0 121 d3.isQuantized = false;
matthiasm@0 122 d3.sampleType = OutputDescriptor::FixedSampleRate;
matthiasm@0 123 d3.hasDuration = false;
matthiasm@0 124 d3.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
matthiasm@0 125 list.push_back(d3);
Chris@35 126 m_outputSemiSpec = index++;
matthiasm@0 127
matthiasm@0 128 OutputDescriptor d4;
matthiasm@0 129 d4.identifier = "chroma";
matthiasm@0 130 d4.name = "Chromagram";
matthiasm@0 131 d4.description = "Tuning-adjusted chromagram from NNLS soft transcription, with an emphasis on the medium note range.";
matthiasm@0 132 d4.unit = "";
matthiasm@0 133 d4.hasFixedBinCount = true;
matthiasm@0 134 d4.binCount = 12;
matthiasm@0 135 d4.binNames = chromanames;
matthiasm@0 136 d4.hasKnownExtents = false;
matthiasm@0 137 d4.isQuantized = false;
matthiasm@0 138 d4.sampleType = OutputDescriptor::FixedSampleRate;
matthiasm@0 139 d4.hasDuration = false;
matthiasm@0 140 d4.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
matthiasm@0 141 list.push_back(d4);
Chris@35 142 m_outputChroma = index++;
matthiasm@0 143
matthiasm@0 144 OutputDescriptor d5;
matthiasm@0 145 d5.identifier = "basschroma";
matthiasm@0 146 d5.name = "Bass Chromagram";
matthiasm@0 147 d5.description = "Tuning-adjusted bass chromagram from NNLS soft transcription, with an emphasis on the bass note range.";
matthiasm@0 148 d5.unit = "";
matthiasm@0 149 d5.hasFixedBinCount = true;
matthiasm@0 150 d5.binCount = 12;
matthiasm@0 151 d5.binNames = chromanames;
matthiasm@0 152 d5.hasKnownExtents = false;
matthiasm@0 153 d5.isQuantized = false;
matthiasm@0 154 d5.sampleType = OutputDescriptor::FixedSampleRate;
matthiasm@0 155 d5.hasDuration = false;
matthiasm@0 156 d5.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
matthiasm@0 157 list.push_back(d5);
Chris@35 158 m_outputBassChroma = index++;
matthiasm@0 159
matthiasm@0 160 OutputDescriptor d6;
matthiasm@0 161 d6.identifier = "bothchroma";
matthiasm@0 162 d6.name = "Chromagram and Bass Chromagram";
matthiasm@0 163 d6.description = "Tuning-adjusted chromagram and bass chromagram (stacked on top of each other) from NNLS soft transcription.";
matthiasm@0 164 d6.unit = "";
matthiasm@0 165 d6.hasFixedBinCount = true;
matthiasm@0 166 d6.binCount = 24;
matthiasm@0 167 d6.binNames = bothchromanames;
matthiasm@0 168 d6.hasKnownExtents = false;
matthiasm@0 169 d6.isQuantized = false;
matthiasm@0 170 d6.sampleType = OutputDescriptor::FixedSampleRate;
matthiasm@0 171 d6.hasDuration = false;
matthiasm@0 172 d6.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
matthiasm@0 173 list.push_back(d6);
Chris@35 174 m_outputBothChroma = index++;
matthiasm@1 175
matthiasm@0 176 return list;
matthiasm@0 177 }
matthiasm@0 178
matthiasm@0 179
matthiasm@0 180 bool
matthiasm@0 181 NNLSChroma::initialise(size_t channels, size_t stepSize, size_t blockSize)
matthiasm@0 182 {
Chris@23 183 if (debug_on) {
Chris@23 184 cerr << "--> initialise";
Chris@23 185 }
matthiasm@1 186
Chris@35 187 if (!NNLSBase::initialise(channels, stepSize, blockSize)) {
Chris@35 188 return false;
Chris@35 189 }
matthiasm@1 190
matthiasm@0 191 return true;
matthiasm@0 192 }
matthiasm@0 193
matthiasm@0 194 void
matthiasm@0 195 NNLSChroma::reset()
matthiasm@0 196 {
Chris@23 197 if (debug_on) cerr << "--> reset";
Chris@35 198 NNLSBase::reset();
matthiasm@0 199 }
matthiasm@0 200
matthiasm@0 201 NNLSChroma::FeatureSet
matthiasm@0 202 NNLSChroma::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
matthiasm@0 203 {
Chris@23 204 if (debug_on) cerr << "--> process" << endl;
Chris@35 205
Chris@35 206 NNLSBase::baseProcess(inputBuffers, timestamp);
matthiasm@0 207
Chris@23 208 FeatureSet fs;
Chris@35 209 fs[m_outputLogSpec].push_back(m_logSpectrum[m_logSpectrum.size()-1]);
Chris@23 210 return fs;
matthiasm@0 211 }
matthiasm@0 212
matthiasm@0 213 NNLSChroma::FeatureSet
matthiasm@0 214 NNLSChroma::getRemainingFeatures()
matthiasm@0 215 {
Chris@23 216 if (debug_on) cerr << "--> getRemainingFeatures" << endl;
Chris@23 217 FeatureSet fsOut;
Chris@35 218 if (m_logSpectrum.size() == 0) return fsOut;
Chris@23 219 //
Chris@23 220 /** Calculate Tuning
Chris@23 221 calculate tuning from (using the angle of the complex number defined by the
Chris@23 222 cumulative mean real and imag values)
Chris@23 223 **/
Chris@23 224 float meanTuningImag = sinvalue * m_meanTuning1 - sinvalue * m_meanTuning2;
Chris@23 225 float meanTuningReal = m_meanTuning0 + cosvalue * m_meanTuning1 + cosvalue * m_meanTuning2;
Chris@23 226 float cumulativetuning = 440 * pow(2,atan2(meanTuningImag, meanTuningReal)/(24*M_PI));
Chris@23 227 float normalisedtuning = atan2(meanTuningImag, meanTuningReal)/(2*M_PI);
Chris@23 228 int intShift = floor(normalisedtuning * 3);
Chris@23 229 float intFactor = normalisedtuning * 3 - intShift; // intFactor is a really bad name for this
matthiasm@1 230
Chris@23 231 char buffer0 [50];
matthiasm@1 232
Chris@23 233 sprintf(buffer0, "estimated tuning: %0.1f Hz", cumulativetuning);
matthiasm@1 234
Chris@23 235 // cerr << "normalisedtuning: " << normalisedtuning << '\n';
matthiasm@1 236
Chris@23 237 /** Tune Log-Frequency Spectrogram
Chris@23 238 calculate a tuned log-frequency spectrogram (f2): use the tuning estimated above (kinda f0) to
Chris@23 239 perform linear interpolation on the existing log-frequency spectrogram (kinda f1).
Chris@23 240 **/
Chris@23 241 cerr << endl << "[NNLS Chroma Plugin] Tuning Log-Frequency Spectrogram ... ";
matthiasm@13 242
Chris@23 243 float tempValue = 0;
Chris@23 244 float dbThreshold = 0; // relative to the background spectrum
Chris@23 245 float thresh = pow(10,dbThreshold/20);
Chris@23 246 // cerr << "tune local ? " << m_tuneLocal << endl;
Chris@23 247 int count = 0;
matthiasm@1 248
Chris@35 249 for (FeatureList::iterator i = m_logSpectrum.begin(); i != m_logSpectrum.end(); ++i) {
Chris@23 250 Feature f1 = *i;
Chris@23 251 Feature f2; // tuned log-frequency spectrum
Chris@23 252 f2.hasTimestamp = true;
Chris@23 253 f2.timestamp = f1.timestamp;
Chris@23 254 f2.values.push_back(0.0); f2.values.push_back(0.0); // set lower edge to zero
matthiasm@1 255
Chris@23 256 if (m_tuneLocal) {
Chris@23 257 intShift = floor(m_localTuning[count] * 3);
Chris@23 258 intFactor = m_localTuning[count] * 3 - intShift; // intFactor is a really bad name for this
Chris@23 259 }
matthiasm@1 260
Chris@23 261 // cerr << intShift << " " << intFactor << endl;
matthiasm@1 262
Chris@23 263 for (unsigned k = 2; k < f1.values.size() - 3; ++k) { // interpolate all inner bins
Chris@23 264 tempValue = f1.values[k + intShift] * (1-intFactor) + f1.values[k+intShift+1] * intFactor;
Chris@23 265 f2.values.push_back(tempValue);
Chris@23 266 }
matthiasm@1 267
Chris@23 268 f2.values.push_back(0.0); f2.values.push_back(0.0); f2.values.push_back(0.0); // upper edge
Chris@23 269 vector<float> runningmean = SpecialConvolution(f2.values,hw);
Chris@23 270 vector<float> runningstd;
Chris@23 271 for (int i = 0; i < 256; i++) { // first step: squared values into vector (variance)
Chris@23 272 runningstd.push_back((f2.values[i] - runningmean[i]) * (f2.values[i] - runningmean[i]));
Chris@23 273 }
Chris@23 274 runningstd = SpecialConvolution(runningstd,hw); // second step convolve
Chris@23 275 for (int i = 0; i < 256; i++) {
Chris@23 276 runningstd[i] = sqrt(runningstd[i]); // square root to finally have running std
Chris@23 277 if (runningstd[i] > 0) {
Chris@23 278 // f2.values[i] = (f2.values[i] / runningmean[i]) > thresh ?
Chris@23 279 // (f2.values[i] - runningmean[i]) / pow(runningstd[i],m_paling) : 0;
Chris@23 280 f2.values[i] = (f2.values[i] - runningmean[i]) > 0 ?
Chris@23 281 (f2.values[i] - runningmean[i]) / pow(runningstd[i],m_paling) : 0;
Chris@23 282 }
Chris@23 283 if (f2.values[i] < 0) {
Chris@23 284 cerr << "ERROR: negative value in logfreq spectrum" << endl;
Chris@23 285 }
Chris@23 286 }
Chris@35 287 fsOut[m_outputTunedSpec].push_back(f2);
Chris@23 288 count++;
Chris@23 289 }
Chris@23 290 cerr << "done." << endl;
matthiasm@1 291
Chris@23 292 /** Semitone spectrum and chromagrams
Chris@23 293 Semitone-spaced log-frequency spectrum derived from the tuned log-freq spectrum above. the spectrum
Chris@23 294 is inferred using a non-negative least squares algorithm.
Chris@23 295 Three different kinds of chromagram are calculated, "treble", "bass", and "both" (which means
Chris@23 296 bass and treble stacked onto each other).
Chris@23 297 **/
Chris@23 298 if (m_dictID == 1) {
Chris@23 299 cerr << "[NNLS Chroma Plugin] Mapping to semitone spectrum and chroma ... ";
Chris@23 300 } else {
Chris@23 301 cerr << "[NNLS Chroma Plugin] Performing NNLS and mapping to chroma ... ";
Chris@23 302 }
matthiasm@13 303
matthiasm@1 304
Chris@23 305 vector<float> oldchroma = vector<float>(12,0);
Chris@23 306 vector<float> oldbasschroma = vector<float>(12,0);
Chris@23 307 count = 0;
matthiasm@9 308
Chris@23 309 for (FeatureList::iterator it = fsOut[2].begin(); it != fsOut[2].end(); ++it) {
Chris@23 310 Feature f2 = *it; // logfreq spectrum
Chris@23 311 Feature f3; // semitone spectrum
Chris@23 312 Feature f4; // treble chromagram
Chris@23 313 Feature f5; // bass chromagram
Chris@23 314 Feature f6; // treble and bass chromagram
matthiasm@1 315
Chris@23 316 f3.hasTimestamp = true;
Chris@23 317 f3.timestamp = f2.timestamp;
matthiasm@1 318
Chris@23 319 f4.hasTimestamp = true;
Chris@23 320 f4.timestamp = f2.timestamp;
matthiasm@1 321
Chris@23 322 f5.hasTimestamp = true;
Chris@23 323 f5.timestamp = f2.timestamp;
matthiasm@1 324
Chris@23 325 f6.hasTimestamp = true;
Chris@23 326 f6.timestamp = f2.timestamp;
matthiasm@1 327
Chris@35 328 float b[256];
matthiasm@1 329
Chris@23 330 bool some_b_greater_zero = false;
Chris@23 331 float sumb = 0;
Chris@23 332 for (int i = 0; i < 256; i++) {
Chris@23 333 // b[i] = m_dict[(256 * count + i) % (256 * 84)];
Chris@23 334 b[i] = f2.values[i];
Chris@23 335 sumb += b[i];
Chris@23 336 if (b[i] > 0) {
Chris@23 337 some_b_greater_zero = true;
Chris@23 338 }
Chris@23 339 }
matthiasm@1 340
Chris@23 341 // here's where the non-negative least squares algorithm calculates the note activation x
matthiasm@1 342
Chris@23 343 vector<float> chroma = vector<float>(12, 0);
Chris@23 344 vector<float> basschroma = vector<float>(12, 0);
Chris@23 345 float currval;
Chris@23 346 unsigned iSemitone = 0;
matthiasm@1 347
Chris@23 348 if (some_b_greater_zero) {
Chris@23 349 if (m_dictID == 1) {
Chris@23 350 for (unsigned iNote = 2; iNote < nNote - 2; iNote += 3) {
Chris@23 351 currval = 0;
Chris@23 352 currval += b[iNote + 1 + -1] * 0.5;
Chris@23 353 currval += b[iNote + 1 + 0] * 1.0;
Chris@23 354 currval += b[iNote + 1 + 1] * 0.5;
Chris@23 355 f3.values.push_back(currval);
Chris@23 356 chroma[iSemitone % 12] += currval * treblewindow[iSemitone];
Chris@23 357 basschroma[iSemitone % 12] += currval * basswindow[iSemitone];
Chris@23 358 iSemitone++;
Chris@23 359 }
matthiasm@1 360
Chris@23 361 } else {
Chris@35 362 float x[84+1000];
Chris@23 363 for (int i = 1; i < 1084; ++i) x[i] = 1.0;
Chris@23 364 vector<int> signifIndex;
Chris@23 365 int index=0;
Chris@23 366 sumb /= 84.0;
Chris@23 367 for (unsigned iNote = 2; iNote < nNote - 2; iNote += 3) {
Chris@23 368 float currval = 0;
Chris@35 369 currval += b[iNote + 1 + -1];
Chris@35 370 currval += b[iNote + 1 + 0];
Chris@23 371 currval += b[iNote + 1 + 1];
Chris@23 372 if (currval > 0) signifIndex.push_back(index);
Chris@23 373 f3.values.push_back(0); // fill the values, change later
Chris@23 374 index++;
Chris@23 375 }
Chris@35 376 float rnorm;
Chris@35 377 float w[84+1000];
Chris@35 378 float zz[84+1000];
Chris@23 379 int indx[84+1000];
Chris@23 380 int mode;
Chris@23 381 int dictsize = 256*signifIndex.size();
Chris@23 382 // cerr << "dictsize is " << dictsize << "and values size" << f3.values.size()<< endl;
Chris@35 383 float *curr_dict = new float[dictsize];
Chris@23 384 for (unsigned iNote = 0; iNote < signifIndex.size(); ++iNote) {
Chris@23 385 for (unsigned iBin = 0; iBin < 256; iBin++) {
Chris@23 386 curr_dict[iNote * 256 + iBin] = 1.0 * m_dict[signifIndex[iNote] * 256 + iBin];
Chris@23 387 }
Chris@23 388 }
Chris@35 389 nnls(curr_dict, nNote, nNote, signifIndex.size(), b, x, &rnorm, w, zz, indx, &mode);
Chris@23 390 delete [] curr_dict;
Chris@23 391 for (unsigned iNote = 0; iNote < signifIndex.size(); ++iNote) {
Chris@23 392 f3.values[signifIndex[iNote]] = x[iNote];
Chris@23 393 // cerr << mode << endl;
Chris@23 394 chroma[signifIndex[iNote] % 12] += x[iNote] * treblewindow[signifIndex[iNote]];
Chris@23 395 basschroma[signifIndex[iNote] % 12] += x[iNote] * basswindow[signifIndex[iNote]];
Chris@23 396 }
Chris@23 397 }
Chris@23 398 }
matthiasm@13 399
Chris@23 400 f4.values = chroma;
Chris@23 401 f5.values = basschroma;
Chris@23 402 chroma.insert(chroma.begin(), basschroma.begin(), basschroma.end()); // just stack the both chromas
Chris@23 403 f6.values = chroma;
matthiasm@1 404
Chris@23 405 if (m_doNormalizeChroma > 0) {
Chris@23 406 vector<float> chromanorm = vector<float>(3,0);
Chris@23 407 switch (int(m_doNormalizeChroma)) {
Chris@23 408 case 0: // should never end up here
Chris@23 409 break;
Chris@23 410 case 1:
Chris@23 411 chromanorm[0] = *max_element(f4.values.begin(), f4.values.end());
Chris@23 412 chromanorm[1] = *max_element(f5.values.begin(), f5.values.end());
Chris@23 413 chromanorm[2] = max(chromanorm[0], chromanorm[1]);
Chris@23 414 break;
Chris@23 415 case 2:
Chris@23 416 for (vector<float>::iterator it = f4.values.begin(); it != f4.values.end(); ++it) {
Chris@23 417 chromanorm[0] += *it;
Chris@23 418 }
Chris@23 419 for (vector<float>::iterator it = f5.values.begin(); it != f5.values.end(); ++it) {
Chris@23 420 chromanorm[1] += *it;
Chris@23 421 }
Chris@23 422 for (vector<float>::iterator it = f6.values.begin(); it != f6.values.end(); ++it) {
Chris@23 423 chromanorm[2] += *it;
Chris@23 424 }
Chris@23 425 break;
Chris@23 426 case 3:
Chris@23 427 for (vector<float>::iterator it = f4.values.begin(); it != f4.values.end(); ++it) {
Chris@23 428 chromanorm[0] += pow(*it,2);
Chris@23 429 }
Chris@23 430 chromanorm[0] = sqrt(chromanorm[0]);
Chris@23 431 for (vector<float>::iterator it = f5.values.begin(); it != f5.values.end(); ++it) {
Chris@23 432 chromanorm[1] += pow(*it,2);
Chris@23 433 }
Chris@23 434 chromanorm[1] = sqrt(chromanorm[1]);
Chris@23 435 for (vector<float>::iterator it = f6.values.begin(); it != f6.values.end(); ++it) {
Chris@23 436 chromanorm[2] += pow(*it,2);
Chris@23 437 }
Chris@23 438 chromanorm[2] = sqrt(chromanorm[2]);
Chris@23 439 break;
Chris@23 440 }
Chris@23 441 if (chromanorm[0] > 0) {
Chris@23 442 for (int i = 0; i < f4.values.size(); i++) {
Chris@23 443 f4.values[i] /= chromanorm[0];
Chris@23 444 }
Chris@23 445 }
Chris@23 446 if (chromanorm[1] > 0) {
Chris@23 447 for (int i = 0; i < f5.values.size(); i++) {
Chris@23 448 f5.values[i] /= chromanorm[1];
Chris@23 449 }
Chris@23 450 }
Chris@23 451 if (chromanorm[2] > 0) {
Chris@23 452 for (int i = 0; i < f6.values.size(); i++) {
Chris@23 453 f6.values[i] /= chromanorm[2];
Chris@23 454 }
Chris@23 455 }
Chris@23 456 }
matthiasm@13 457
Chris@35 458 fsOut[m_outputSemiSpec].push_back(f3);
Chris@35 459 fsOut[m_outputChroma].push_back(f4);
Chris@35 460 fsOut[m_outputBassChroma].push_back(f5);
Chris@35 461 fsOut[m_outputBothChroma].push_back(f6);
Chris@23 462 count++;
Chris@23 463 }
Chris@23 464 cerr << "done." << endl;
matthiasm@10 465
Chris@23 466 return fsOut;
matthiasm@0 467
matthiasm@0 468 }
matthiasm@0 469